南側門 進入

This commit is contained in:
威勝 張 2024-04-29 18:20:32 +08:00
parent 5251bcffee
commit cc9d935424
73 changed files with 75350 additions and 13 deletions

View File

@ -11,7 +11,7 @@ import urllib3
import time import time
from requests.structures import CaseInsensitiveDict from requests.structures import CaseInsensitiveDict
import base64 import base64
from Class.Gate_class import Gate_in_class from Class.South_class import South_in_class
urllib3.disable_warnings() urllib3.disable_warnings()
import pandas as pd import pandas as pd
@ -23,7 +23,7 @@ import pandas as pd
if __name__ == '__main__': if __name__ == '__main__':
T = Gate_in_class() T = South_in_class()
T.start() T.start()
while True: while True:
try: try:
@ -33,7 +33,7 @@ if __name__ == '__main__':
T.terminate() T.terminate()
print(f'重啟中') print(f'重啟中')
time.sleep(5) time.sleep(5)
T = Gate_in_class() T = South_in_class()
T.start() T.start()
print(f'重啟完成') print(f'重啟完成')
time.sleep(0.2) time.sleep(0.2)

View File

@ -51,7 +51,7 @@ class Parking_spaces_API():
class Gate_API(): class South_API():
def __init__(self): def __init__(self):
self.token = self.User_token()['token'] self.token = self.User_token()['token']

View File

@ -0,0 +1,351 @@
import multiprocessing as mp
import threading
import cv2
import sys, time, os
import base64
from collections import Counter
import re
from flask import render_template
from flask import Flask, request, jsonify
from pyModbusTCP.client import ModbusClient
import datetime
import shutil
class IOcard(threading.Thread):
def __init__(self, SERVER_HOST, SERVER_PORT): # ,parent=None):
threading.Thread.__init__(self)
self.SERVER_HOST = SERVER_HOST
self.SERVER_PORT = SERVER_PORT
self.connect = False
self.running = False
self._outputFlag = False
self._outputBit = "0000"
self._client = None
def IOCard_connect(self):
self._client = ModbusClient(host=self.SERVER_HOST, port=self.SERVER_PORT, timeout=5)
if self._client.open():
print(f'IO連線成功')
self.connect = True
self.running = False
else:
print('斷線...')
self.connect = False
self.running = False
def run(self):
outputBit = ""
while self.running and self.connect:
if outputBit != self._outputBit:
self.switch(self._outputBit)
outputBit = self._outputBit
self._outputFlag = False
time.sleep(1 / 100)
# if not self._client.is_open:
# print('未連線')
# self.rst_connect()
def rst_connect(self):
if self._client.is_open:
print(f'斷線重連成功')
time.sleep(1)
# region IO
def _send0000(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x00, 0x00, 0x00])
return is_ok
def _send0001(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x00, 0x00, 0x00])
return is_ok
def _send0010(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x01, 0x00, 0x00])
return is_ok
def _send0011(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x01, 0x00, 0x00])
return is_ok
def _send0100(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x00, 0x01, 0x00])
return is_ok
def _send0101(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x00, 0x01, 0x00])
return is_ok
def _send0110(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x01, 0x01, 0x00])
return is_ok
def _send0111(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x01, 0x01, 0x00])
return is_ok
def _send1000(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x00, 0x00, 0x01])
return is_ok
def _send1001(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x00, 0x00, 0x01])
return is_ok
def _send1010(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x01, 0x00, 0x01])
return is_ok
def _send1011(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x01, 0x00, 0x01])
return is_ok
def _send1100(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x00, 0x01, 0x01])
return is_ok
def _send1101(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x00, 0x01, 0x01])
return is_ok
def _send1110(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x00, 0x01, 0x01, 0x01])
return is_ok
def _send1111(self):
if self.connect:
is_ok = self._client.write_multiple_coils(0x00, [0x01, 0x01, 0x01, 0x01])
return is_ok
def _readInput(self):
response = self._client.read_discrete_inputs(0, 4)
return response
# endregion
def switch(self, lang):
if lang == "0000":
self._send0000()
elif lang == "0001":
self._send0001()
elif lang == "0010":
self._send0010()
elif lang == "0011":
self._send0011()
elif lang == "0100":
self._send0100()
elif lang == "0101":
self._send0101()
elif lang == "0110":
self._send0110()
elif lang == "0111":
self._send0111()
elif lang == "1000":
self._send1000()
elif lang == "1001":
self._send1001()
elif lang == "1010":
self._send1010()
elif lang == "1011":
self._send1011()
elif lang == "1100":
self._send1100()
elif lang == "1101":
self._send1101()
elif lang == "1110":
self._send1110()
elif lang == "1111":
self._send1111()
def open(self):
if self.connect:
self.running = True
def stop(self):
if self.connect:
self.running = False
def close(self):
if self.connect:
self.running = False
time.sleep(1)
self._client.close()
def go_home(self):
self._outputFlag = True
self._outputBit = "0000"
def do_function(self, str):
self._outputFlag = True
self._outputBit = str
class IO_class():
def __init__(self, ip):
self.IP = ip
self.connect_check = False
self.connect_clicked()
self.init_io()
def init_io(self):
self.io_1 = "0"
self.io_2 = "0"
self.io_3 = "0"
self.io_4 = "0"
def connect_clicked(self):
self.IOCardThread = IOcard(SERVER_HOST=self.IP, SERVER_PORT=10001)
self.IOCardThread.IOCard_connect()
if self.IOCardThread.connect:
self.IOCardThread.open()
self.IOCardThread.start()
self.connect_check = True
def out_1_clicked(self):
self.io_1 = "1"
self.out_io()
def out_2_clicked(self):
self.io_2 = "1"
self.out_io()
def out_3_clicked(self):
self.io_3 = "1"
self.out_io()
def out_4_clicked(self):
self.io_4 = "1"
self.out_io()
def out_all_clicked(self):
self.io_1 = "1"
self.io_2 = "1"
self.io_3 = "1"
self.io_4 = "1"
self.out_io()
def break_1_clicked(self):
self.io_1 = "0"
self.out_io()
def break_2_clicked(self):
self.io_2 = "0"
self.out_io()
def break_3_clicked(self):
self.io_3 = "0"
self.out_io()
def break_4_clicked(self):
self.io_4 = "0"
self.out_io()
def break_all_clicked(self):
self.io_1 = "0"
self.io_2 = "0"
self.io_3 = "0"
self.io_4 = "0"
self.out_io()
def out_io(self):
if self.connect_check and self.IOCardThread.connect:
str = self.io_1 + self.io_2 + self.io_3 + self.io_4
self.IOCardThread.do_function(str)
# str_text=""
# if self.io_1=="1":
# str_text = str_text+"IO1 啟動 \n"
# if self.io_2=="1":
# str_text = str_text+"IO2 啟動 \n"
# if self.io_3=="1":
# str_text = str_text+"IO3 啟動 \n"
# if self.io_4=="1":
# str_text = str_text+"IO4 啟動 \n"
# self.out_text.setText(str_text)
else:
# self.out_text.setText("尚未連接IO卡")
print("尚未連接IO卡")
class IO_Webapi(threading.Thread):
def __init__(self, ip):
threading.Thread.__init__(self)
self.app = Flask(__name__)
if ip == "192.168.100.201":
self.port = 6001
else:
self.port = 6002
self.IO = IO_class(ip)
# 将路由函数与根路径关联
# HTML
self.app.add_url_rule('/', 'index', self.index)
# API
self.app.add_url_rule('/io_1_open', 'IO_1_open', self.IO_1_open)
self.app.add_url_rule('/io_2_open', 'IO_2_open', self.IO_2_open)
self.app.add_url_rule('/io_3_open', 'IO_3_open', self.IO_3_open)
self.app.add_url_rule('/io_4_open', 'IO_4_open', self.IO_4_open)
self.app.add_url_rule('/io_1_close', 'IO_1_colse', self.IO_1_close)
self.app.add_url_rule('/io_2_close', 'IO_2_colse', self.IO_2_close)
self.app.add_url_rule('/io_3_close', 'IO_3_colse', self.IO_3_close)
self.app.add_url_rule('/io_4_close', 'IO_4_colse', self.IO_4_close)
def run(self):
# self.app.run()
self.app.run(host="0.0.0.0", port=self.port)
def index(self):
return render_template('test_1110_index.html')
# region API
def IO_1_open(self):
self.IO.out_1_clicked()
time.sleep(1)
self.IO.break_1_clicked()
return ("200")
def IO_2_open(self):
self.IO.out_2_clicked()
return ("200")
def IO_3_open(self):
self.IO.out_3_clicked()
return ("200")
def IO_4_open(self):
self.IO.out_4_clicked()
return ("200")
def IO_1_close(self):
self.IO.break_1_clicked()
return ("200")
def IO_2_close(self):
self.IO.break_2_clicked()
return ("200")
def IO_3_close(self):
self.IO.break_3_clicked()
return ("200")
def IO_4_close(self):
self.IO.break_4_clicked()
return ("200")
# endregion

View File

@ -16,7 +16,8 @@ from requests.structures import CaseInsensitiveDict
import base64 import base64
from collections import Counter from collections import Counter
import re import re
from Class.API_class import Gate_API from Class.API_class import South_API
from Class.IO_class import IO_Webapi
urllib3.disable_warnings() urllib3.disable_warnings()
import pandas as pd import pandas as pd
@ -48,7 +49,7 @@ class Webcam(threading.Thread):
else: else:
self.cam_on = False self.cam_on = False
self.reconnect_cam() self.reconnect_cam()
time.sleep(0.02) time.sleep(0.05)
@ -79,18 +80,19 @@ class Webcam(threading.Thread):
print(f'.') print(f'.')
time.sleep(0.5) time.sleep(0.5)
class Gate_in_class(mp.Process): class South_in_class(mp.Process):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.organising_data() self.organising_data()
self.api = Gate_API() self.api = South_API()
# 整理資料 # 整理資料
def organising_data(self): def organising_data(self):
url = f'rtsp://admin:mj22797303@192.168.100.12:554/media.amp?streamprofile=Profile1' url = f'rtsp://admin:mj22797303@192.168.100.12:554/media.amp?streamprofile=Profile1'
# url=f'D:\Code\project\parking_space\python\Violation\Version\\test_1218\\video\\test_3\\test_1.mp4' url=f'D:\\Code\\project\\parking_space\\Stable_Python\\Yuntech_NET_Stable_0429\\South_side\\In\\video\\test1.avi'
self.url = url self.url = url
self.CAR_ROI_license_plate=[(20,200),(1500,600)] # 車牌辨識ROI self.CAR_ROI_license_plate=[(20,20),(720,600)] # 車牌辨識ROI
self.IO_IP='192.168.1.200'
def run(self): def run(self):
# 啟動相機 # 啟動相機
@ -116,6 +118,10 @@ class Gate_in_class(mp.Process):
end_time = time.time() end_time = time.time()
print(f'讀取權重 = {end_time - start_time}') print(f'讀取權重 = {end_time - start_time}')
# IO 啟動
self.IO = IO_Webapi(self.IO_IP)
self.IO.start()
# 影片參數 # 影片參數
self.width = int(self.cam.capture.get(cv2.CAP_PROP_FRAME_WIDTH)) self.width = int(self.cam.capture.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cam.capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) self.height = int(self.cam.capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
@ -123,7 +129,14 @@ class Gate_in_class(mp.Process):
self.out = None self.out = None
self.fourcc = cv2.VideoWriter_fourcc(*'XVID') self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
# 白名單
self.white_licence_list = ['2U6539', '7612PR', 'BES9077', 'AJD9977', 'BHY9997', 'AZC0227', 'BXA3959',
'AYB6898', 'X61970', 'BNG6127', 'BQT3959', 'AQG8111', '8672WF', 'NVL3918']
# 演算法 開始 # 演算法 開始
self.open = False
self.open_time = time.time()
self.IO_text = "close"
self.car_info_all_list = { self.car_info_all_list = {
'car_all_serial_number': [], 'car_all_serial_number': [],
'car_all_data': {}, 'car_all_data': {},
@ -147,6 +160,7 @@ class Gate_in_class(mp.Process):
try: try:
self.track_img = self.car_check(cars_data) self.track_img = self.car_check(cars_data)
self.double_check() self.double_check()
self.IO_control()
except BaseException as e: except BaseException as e:
print(e) print(e)
self.track_img = img self.track_img = img
@ -316,7 +330,7 @@ class Gate_in_class(mp.Process):
# 雙重確認 # 雙重確認
def double_check(self): def double_check(self):
serial_number_list = self.car_info_all_list['car_all_serial_number'][-5:] serial_number_list = self.car_info_all_list['car_all_serial_number'][-3:]
for car_serial_number in serial_number_list: for car_serial_number in serial_number_list:
# 若沒檢測到進去但有記錄到5張 # 若沒檢測到進去但有記錄到5張
if self.car_info_all_list['car_all_data'][f'{car_serial_number}']["time"] != None: if self.car_info_all_list['car_all_data'][f'{car_serial_number}']["time"] != None:
@ -342,6 +356,21 @@ class Gate_in_class(mp.Process):
else: else:
print(f'{car_serial_number} - licence = {plate_name}-短時間重複') print(f'{car_serial_number} - licence = {plate_name}-短時間重複')
# IO控制
def IO_control(self):
close_time = time.time()
if self.open == True:
if self.flag_2 == True:
print("open")
self.IO_text = "open"
self.open_time = time.time()
self.flag_2 = False
self.IO.IO.out_1_clicked()
if self.open == True and (close_time - self.open_time) > 1:
self.IO.IO.break_1_clicked()
self.IO_text = "close"
print("close")
self.open = False
@ -357,7 +386,7 @@ class Gate_in_class(mp.Process):
c = 1 c = 1
# 修改大小 # 修改大小
img = cv2.resize(img, (int(width / c), int(height / c))) img = cv2.resize(img, (int(width / c), int(height / c)))
cv2.imshow(f'Yuntech-in', img) cv2.imshow(f'South-in', img)
cv2.waitKey(1) cv2.waitKey(1)
# 畫ROI # 畫ROI
@ -406,12 +435,16 @@ class Gate_in_class(mp.Process):
license_plate_number = self.car_info_all_list["car_all_data"][f"{car_serial_number}"][ license_plate_number = self.car_info_all_list["car_all_data"][f"{car_serial_number}"][
"licence"] "licence"]
data ={ data ={
"location":"大門口", "location":"南側門",
"license_plate_number": license_plate_number, "license_plate_number": license_plate_number,
"car_img": img_base64, "car_img": img_base64,
"in_time": "2024-02-04T19:15:09.4371245+08:00", "in_time": "2024-02-04T19:15:09.4371245+08:00",
"out_time": "2024-02-04T19:15:09.4371245+08:00" "out_time": "2024-02-04T19:15:09.4371245+08:00"
} }
self.flag_2 = True
if license_plate_number in self.white_licence_list:
self.open = True
self.flag_2 = True
try: try:
self.api.post_data(data) self.api.post_data(data)
self.license_plate_number = license_plate_number self.license_plate_number = license_plate_number

View File

@ -0,0 +1,18 @@
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
}

View File

@ -0,0 +1,8 @@
.container {
width: 80%;
margin: 0 auto;
text-align: center;
font-family: sans-serif;
font-size: 20px;
padding-top: 100px;
}

View File

@ -0,0 +1,4 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,427 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,424 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
Copyright (c) .NET Foundation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
these files except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

View File

@ -0,0 +1,432 @@
// Unobtrusive validation support library for jQuery and jQuery Validate
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version v3.2.11
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like environments that support module.exports
module.exports = factory(require('jquery-validation'));
} else {
// Browser global
jQuery.validator.unobtrusive = factory(jQuery);
}
}(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}
function escapeAttributeValue(value) {
// As mentioned on http://api.jquery.com/category/selectors/
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onErrors(event, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}
function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer");
if (container) {
var replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
function onReset(event) { // 'this' is the form element
var $form = $(this),
key = '__jquery_unobtrusive_validation_form_reset';
if ($form.data(key)) {
return;
}
// Set a flag that indicates we're currently resetting the form.
$form.data(key, true);
try {
$form.data("validator").resetForm();
} finally {
$form.removeData(key);
}
$form.find(".validation-summary-errors")
.addClass("validation-summary-valid")
.removeClass("validation-summary-errors");
$form.find(".field-validation-error")
.addClass("field-validation-valid")
.removeClass("field-validation-error")
.removeData("unobtrusiveContainer")
.find(">*") // If we were using valmsg-replace, get the underlying error
.removeData("unobtrusiveContainer");
}
function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation),
onResetProxy = $.proxy(onReset, form),
defaultOptions = $jQval.unobtrusive.options || {},
execInContext = function (name, args) {
var func = defaultOptions[name];
func && $.isFunction(func) && func.apply(form, args);
};
if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: defaultOptions.errorClass || "input-validation-error",
errorElement: defaultOptions.errorElement || "span",
errorPlacement: function () {
onError.apply(form, arguments);
execInContext("errorPlacement", arguments);
},
invalidHandler: function () {
onErrors.apply(form, arguments);
execInContext("invalidHandler", arguments);
},
messages: {},
rules: {},
success: function () {
onSuccess.apply(form, arguments);
execInContext("success", arguments);
}
},
attachValidation: function () {
$form
.off("reset." + data_validation, onResetProxy)
.on("reset." + data_validation, onResetProxy)
.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}
return result;
}
$jQval.unobtrusive = {
adapters: [],
parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;
if (!form) { // Cannot do client-side validation without a form
return;
}
valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};
$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";
$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});
this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});
$.extend(rules, { "__dummy__": true });
if (!skipAttach) {
valInfo.attachValidation();
}
},
parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
// element with data-val=true
var $selector = $(selector),
$forms = $selector.parents()
.addBack()
.filter("form")
.add($selector.find("form"))
.has("[data-val=true]");
$selector.find("[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});
$forms.each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};
adapters = $jQval.unobtrusive.adapters;
adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};
adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;
if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};
$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});
$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}
match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
var match;
if (nonalphamin) {
match = value.match(/\W/g);
match = match && match.length >= nonalphamin;
}
return match;
});
if ($jQval.methods.extension) {
adapters.addSingleVal("accept", "mimtype");
adapters.addSingleVal("extension", "extension");
} else {
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
// validating the extension, and ignore mime-type validations as they are not supported.
adapters.addSingleVal("extension", "extension", "accept");
}
adapters.addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
// For checkboxes and radio buttons, only pick up values from checked fields.
if (field.is(":checkbox")) {
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
}
else if (field.is(":radio")) {
return field.filter(":checked").val() || '';
}
return field.val();
};
});
setValidationValues(options, "remote", value);
});
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
if (options.params.min) {
setValidationValues(options, "minlength", options.params.min);
}
if (options.params.nonalphamin) {
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
}
if (options.params.regex) {
setValidationValues(options, "regex", options.params.regex);
}
});
adapters.add("fileextensions", ["extensions"], function (options) {
setValidationValues(options, "extension", options.params.extensions);
});
$(function () {
$jQval.unobtrusive.parse(document);
});
return $jQval.unobtrusive;
}));

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
=====================
Copyright Jörn Zaefferer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,36 @@
Copyright JS Foundation and other contributors, https://js.foundation/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/jquery/jquery
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
All files located in the node_modules and external directories are
externally maintained libraries used by this software which have their
own licenses; we recommend you read them, as their terms may differ from
the terms above.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,251 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='lib/bootstrap/dist/css/bootstrap.min.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static', filename='css/site.css') }}" asp-append-version="true"/>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
<script src="{{ url_for('static', filename='js/site.js') }}"></script>
<script src="{{ url_for('static', filename='lib/bootstrap/dist/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='lib/jquery/dist/jquery.min.js') }}" asp-append-version="true"></script>
</head>
<body>
<input type="hidden" id="parking_spaces_name_id" value='{{ id }}' />
<h1>停車區-即時停車位</h1>
<div class="size2">
<button class="btn btn-primary" onclick="time_show()">新增車輛</button>
<table class="table">
<thead>
<tr>
<th>
停車區域
</th>
<th>
車牌號碼
</th>
<th>
圖片
</th>
<th>
進入時間
</th>
<th></th>
</tr>
</thead>
<tbody id="demo">
</tbody>
</table>
</div>
<!--彈跳視窗-->
<div>
<dialog id="add_car_view" style="width:100%;">
<div>
<button class="btn btn-danger" style="float:right" onclick="add_car_view.close();"> 關閉</button>
停車區名稱 : @parking_spaces_name </br></br>
車牌號碼 : <input type="text" id="add_license_plate_number_text_id"/></br></br>
圖 片 : <input type="text" id="add_car_img_text_id"/></br></br>
進入時間 : <input type="text" id="add_in_time_text_id"/></br></br>
<button class="btn btn-success" onclick="add_car()">上傳</button>
</div>
</dialog>
</div>
<!--上傳資料-->
<script>
function add_car() {
var parking_spaces_name = document.getElementById("parking_spaces_name_id").value;
var license_plate_number = document.getElementById("add_license_plate_number_text_id").value;
var car_img = document.getElementById("add_car_img_text_id").value;
var in_time = document.getElementById("add_in_time_text_id").value;
var out_time = ""
var obj = {
parking_spaces_name: parking_spaces_name,
license_plate_number: license_plate_number,
car_img: car_img,
in_time: in_time,
out_time: out_time,
}
//var obj = { parking_spaces_name: parking_spaces_name,license_plate_number: license_plate_number,car_img: car_img,in_time: in_time,out_time:"",}
var stringify_obj = JSON.stringify(obj);
console.log(stringify_obj)
$.ajax({
type: "Post",
url: "http://140.125.21.65:7700/api/Parking_spaces_instant",
//data: {test_id: test_id, test_date: test_date, test_time: test_time, test_analyst: test_analyst, img: img, data_creat_time: "2022-10-04T18:47:40.887014" },
data: stringify_obj,
contentType: "application/json",
success: function (msg) {
console.log(msg)
//add_car_view.close()
add_car_2()
//get_data()
//test_upload_bt_2()
//wait_view()
}
});
}
function add_car_2() {
var parking_spaces_name = document.getElementById("parking_spaces_name_id").value;
var license_plate_number = document.getElementById("add_license_plate_number_text_id").value;
var car_img = document.getElementById("add_car_img_text_id").value;
var in_time = document.getElementById("add_in_time_text_id").value;
var out_time = ""
var obj = {
parking_spaces_name: parking_spaces_name,
license_plate_number: license_plate_number,
car_img: car_img,
in_time: in_time,
out_time: out_time,
}
//var obj = { parking_spaces_name: parking_spaces_name,license_plate_number: license_plate_number,car_img: car_img,in_time: in_time,out_time:"",}
var stringify_obj = JSON.stringify(obj);
console.log(stringify_obj)
$.ajax({
type: "Post",
url: "http://140.125.21.65:7700/api/Parking_spaces_history",
//data: {test_id: test_id, test_date: test_date, test_time: test_time, test_analyst: test_analyst, img: img, data_creat_time: "2022-10-04T18:47:40.887014" },
data: stringify_obj,
contentType: "application/json",
success: function (msg) {
console.log(msg)
add_car_view.close()
//alert("上傳完成");
get_data()
//test_upload_bt_2()
//wait_view()
}
});
}
</script>
<!--時間-->
<script>
function time_show() {
NowDate = new Date();
Y = NowDate.getFullYear();
M = NowDate.getMonth() + 1;
d = NowDate.getDate();
h = NowDate.getHours();
m = NowDate.getMinutes();
s = NowDate.getSeconds();
document.getElementById("add_in_time_text_id").value = Y + "-" + M + "-" + d + " " + h + ":" + m + ":" + s
add_car_view.showModal()
}
</script>
<!--獲取資料-->
<script>
function get_data() {
var name = document.getElementById("parking_spaces_name_id").value
$.ajax({
type: "GET",
url: "http://140.125.21.65:7700/api/Parking_spaces_instant/parking_space_area-" + name,
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
set_data(Model)
}
});
}
</script>
<!--放置資料-->
<script>
function set_data(Model) {
table = "<tr>";
console.log(Model.length)
if (Model.length > 0) {
for (var i = 0; i < Model.length; i++) {
if (Model[i].parking_spaces_name != null) {
table += "<td>" + Model[i].parking_spaces_name + "</td>"
table += "<td>" + Model[i].license_plate_number + "</td>"
table += "<td>" + Model[i].car_img + "</td>"
table += "<td>" + Model[i].in_time + "</td>"
table += "<td>" + '<button class="btn btn-danger " onclick="delet_data(' + "'" + Model[i].license_plate_number + "'" + ')">刪除</button>'
}
table += "</tr>"
table += "<tr>"
}
}
document.getElementById("demo").innerHTML = table
}
</script>
<!--刪除資料-->
<script>
function delet_data(license_plate_number) {
NowDate = new Date();
Y = NowDate.getFullYear();
M = NowDate.getMonth() + 1;
d = NowDate.getDate();
h = NowDate.getHours();
m = NowDate.getMinutes();
s = NowDate.getSeconds();
var out_time = Y + "/" + M + "/" + d + " " + h + ":" + m
var parking_spaces_name = document.getElementById("parking_spaces_name_id").value;
var license_plate_number_1 = license_plate_number
var car_img = document.getElementById("add_car_img_text_id").value;
var in_time = document.getElementById("add_in_time_text_id").value;
var obj = {
parking_spaces_name: parking_spaces_name,
license_plate_number: license_plate_number_1,
car_img: car_img,
in_time: "",
out_time: out_time,
}
var stringify_obj = JSON.stringify(obj);
console.log(stringify_obj)
$.ajax({
type: "Post",
url: "http://140.125.21.65:7700/api/Parking_spaces_history",
data: stringify_obj,
contentType: "application/json",
success: function (msg) {
console.log(msg)
delet_data_2(license_plate_number)
}
});
}
function delet_data_2(license_plate_number) {
$.ajax({
type: "DELETE",
url: "http://140.125.21.65:7700/api/Parking_spaces_instant/" + license_plate_number,
data: {},
contentType: "application/json",
success: function (msg) {
console.log(msg)
get_data()
}
});
}
</script>
<!--開機自啟-->
<script>
window.onload = get_data;
</script>
</body>
</html>

View File

@ -0,0 +1,229 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Flask HTML CSS Example</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='lib/bootstrap/dist/css/bootstrap.min.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static', filename='css/site.css') }}" asp-append-version="true"/>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
<script src="{{ url_for('static', filename='js/site.js') }}"></script>
<script src="{{ url_for('static', filename='lib/bootstrap/dist/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='lib/jquery/dist/jquery.min.js') }}" asp-append-version="true"></script>
</head>
<body>
<h1>校園總停車區域</h1>
<div class="size2">
<button class="btn btn-primary" onclick="add_park_space_view.showModal()">新增停車區</button>
<button style="height:30px;float:right " class="btn btn-outline-secondary" onclick="serch_click()">搜尋</button>
<input type="text" style="float:right" placeholder="請輸入您的車牌" id="serch_text_id"/>
<table class="table">
<thead>
<tr>
<th>
停車區域
</th>
<th>
總車位
</th>
<th>
剩餘車位
</th>
<th>
</th>
</tr>
</thead>
<tbody id="demo">
</tbody>
</table>
</div>
<!--新增停車場-彈跳視窗-->
<div>
<dialog id="add_park_space_view" style="width:100%;">
<div>
<button class="btn btn-danger" style="float:right" onclick="add_park_space_view.close();"> 關閉</button>
停車區名稱 : <input type="text" id="add_park_space_name_text_id"/></br></br>
停車位數量 : <input type="text" id="add_park_space_num_text_id"/></br></br>
<button class="btn btn-success" onclick="add_park_space()">上傳</button>
</div>
</dialog>
</div>
<!--顯示車輛位置-彈跳視窗-->
<div>
<dialog id="serch_view" style="width:100%;">
<div>
<button class="btn btn-danger" style="float:right" onclick="serch_view.close();"> 關閉</button>
停車區名稱 : <input type="text" id="park_space_name_text_id"/> </br></br>
車牌號碼 : <input type="text" id="license_plate_number_text_id"/></br></br>
圖 片 : <input type="text" id="car_img_text_id"/></br></br>
進入時間 : <input type="text" id="in_time_text_id"/></br></br>
</div>
</dialog>
</div>
<!--透過車牌號碼搜尋-->
<script>
function serch_click() {
var license_plate_number = document.getElementById("serch_text_id").value
$.ajax({
type: "GET",
url: "http://140.125.21.65:7700/api/Parking_spaces_instant/license_plate_number-" + license_plate_number,
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
document.getElementById("park_space_name_text_id").value = Model[0].parking_spaces_name
document.getElementById("license_plate_number_text_id").value = Model[0].license_plate_number
document.getElementById("car_img_text_id").value = Model[0].car_img
document.getElementById("in_time_text_id").value = Model[0].in_time
serch_view.showModal()
//set_data(Model)
}
});
}
</script>
<!--獲取資料-->
<script>
function get_data() {
$.ajax({
type: "GET",
url: "http://140.125.21.65:7700/api/Parking_spaces_total_table",
data: {},
contentType: "application/json",
success: function (Model) {
//console.log(Model)
set_data(Model)
}
});
}
</script>
<!--放置資料-->
<script>
function set_data(Model) {
table = "<tr>";
//console.log(Model.length)
if (Model.length > 0) {
for (var i = 0; i < Model.length; i++) {
if (Model[i].parking_spaces_name != null) {
table += "<td>" + Model[i].parking_spaces_name + "</td>"
table += "<td id='" + Model[i].parking_spaces_name + "_total'>" + Model[i].parking_spaces_total_num + "</td>"
table += "<td id='" + Model[i].parking_spaces_name + "_now'>" + "</td>"
get_single_parking_space_car(Model[i].parking_spaces_name)
//table += "<td>" + '<button class="btn btn-danger " onclick="delet_data(' + "'" + Model[i].parking_spaces_name + "'" + ')">刪除</button>'
table += "<td>" + '<button class="btn btn-outline-success " onclick="detail_data(' + "'" + Model[i].parking_spaces_name + "'" + ')">詳細</button>'
table += '<button class="btn btn-outline-warning " onclick="map_data(' + "'" + Model[i].parking_spaces_name + "'" + ')">地圖</button>' + "</td>"
}
table += "</tr>"
table += "<tr>"
}
}
document.getElementById("demo").innerHTML = table
}
</script>
<!--獲取當下停車數量-->
<script>
function get_single_parking_space_car(name) {
$.ajax({
type: "GET",
url: "http://140.125.21.65:7700/api/Parking_spaces_instant/parking_space_area-" + name,
data: {},
contentType: "application/json",
success: function (Model) {
var total = document.getElementById(name + "_total").innerHTML
console.log(total)
var now = Model.length
document.getElementById(name + "_now").innerHTML = total - now
}
});
console.log()
}
</script>
<!--上傳資料-->
<script>
function add_park_space() {
var parking_spaces_name = document.getElementById("add_park_space_name_text_id").value;
var parking_spaces_total_num = document.getElementById("add_park_space_num_text_id").value;
var obj = {parking_spaces_name: parking_spaces_name, parking_spaces_total_num: parking_spaces_total_num}
var stringify_obj = JSON.stringify(obj);
$.ajax({
type: "POST",
url: "http://140.125.21.65:7700/api/Parking_spaces_total_table",
//url: "http://140.125.21.65:7700/api/Postural_Analysis_1",
//data: {test_id: test_id, test_date: test_date, test_time: test_time, test_analyst: test_analyst, img: img, data_creat_time: "2022-10-04T18:47:40.887014" },
data: stringify_obj,
contentType: "application/json",
success: function (msg) {
console.log(msg)
add_park_space_view.close()
alert("上傳完成");
get_data()
//test_upload_bt_2()
//wait_view()
}
});
}
</script>
<!--刪除資料-->
<script>
function delet_data(name) {
$.ajax({
type: "DELETE",
url: "http://140.125.21.65:7700/api/Parking_spaces_total_table/" + name,
data: {},
contentType: "application/json",
success: function (msg) {
console.log(msg)
get_data()
}
});
}
</script>
<!--前往詳細頁面-->
<script>
function detail_data(name) {
window.location = "/detail/" + name;
}
function map_data(name) {
window.location = "/map/" + name;
}
</script>
<!--開機自啟-->
<script>
window.onload = get_data;
</script>
</body>
</html>

View File

@ -0,0 +1,221 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='lib/bootstrap/dist/css/bootstrap.min.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static', filename='css/site.css') }}" asp-append-version="true"/>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
<script src="{{ url_for('static', filename='js/site.js') }}"></script>
<script src="{{ url_for('static', filename='lib/bootstrap/dist/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='lib/jquery/dist/jquery.min.js') }}" asp-append-version="true"></script>
</head>
<body>
<input type="hidden" id="parking_spaces_name_id" value='{{ id }}' />
<!-- css -->
<link rel="stylesheet"
href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<!DOCTYPE html>
<!-- js -->
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin="">
</script>
<style>
html, body {
padding: 0;
margin: 0;
}
#myMap {
width: 1080px;
height: 600px;
}
</style>
<!--地圖-->
<div id="myMap"></div>
<!--獲取資料-->
<script>
var destination
function get_data() {
var name = document.getElementById("parking_spaces_name_id").value
$.ajax({
type: "GET",
url: "http://140.125.21.65:7700/api/Parking_spaces_total_table/" + name,
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
destination = [parseFloat(Model.latitude), parseFloat(Model.longitude)]
getCurrentPosition()
}
});
}
</script>
<!--當前位置-->
<script>
function getCurrentPosition() {
const successCallback = (position) => {
console.log(position.coords.latitude);
console.log(position.coords.longitude);
my_ip = [position.coords.latitude, position.coords.longitude]
//destination = [23.691452, 120.536338]
map_show(destination, my_ip)
};
const errorCallback = (error) => {
console.log(error);
//destination = [23.691452, 120.536338]
map_show(destination, destination)
};
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
}
</script>
<script>
function getCurrentPosition_2() {
const successCallback = (position) => {
console.log(position.coords.latitude);
console.log(position.coords.longitude);
my_ip = [position.coords.latitude, position.coords.longitude]
//my_ip = [position.coords.latitude, position.coords.longitude]
//destination = [23.691452, 120.536338]
map.removeLayer(parking_space_ip)
map.removeLayer(my_car_ip)
map_show_2(destination, my_ip)
};
const errorCallback = (error) => {
console.log(error);
//destination = [23.691452, 120.536338]
map_show_2(destination, destination)
};
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
}
</script>
<!--map_show_停車場位置-->
<script>
var map
function map_show(destination, my_ip) {
var map_center = destination
var fork = [];
map = L.map("myMap", {
center: map_center,
//center: seriesData,
zoom: 17
});
var parking_space_icon = L.icon({
iconUrl: '/image/icon/parking_space_icon.png',
iconSize: [34, 34], // size of the icon
iconAnchor: [27.3, 11.35], // point of the icon which will correspond to marker's location
});
parking_space_ip = L.marker(map_center, {
//icon: parking_space_icon,
title: "",
opacity: 1.0
}).addTo(map);
var car_icon = L.icon({
iconUrl: '/image/icon/car_icon.png',
iconSize: [24, 24], // size of the icon
iconAnchor: [27.3, 11.35], // point of the icon which will correspond to marker's location
});
my_car_ip = L.marker(my_ip, {
//icon: car_icon,
title: "",
opacity: 1.0
}).addTo(map);
//map.removeLayer(parking_space_ip)
//map.removeLayer(my_car_ip)
// 載入圖資
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
window.setTimeout(getCurrentPosition_2, 1000)
}
</script>
<script>
var parking_space_ip
var my_car_ip
function map_show_2(destination, my_ip) {
//map.clearLayers();
var map_center = destination
var fork = [];
var parking_space_icon = L.icon({
iconUrl: '/image/icon/parking_space_icon.png',
iconSize: [34, 34], // size of the icon
iconAnchor: [27.3, 11.35], // point of the icon which will correspond to marker's location
});
parking_space_ip = L.marker(map_center, {
// icon: parking_space_icon,
title: "",
opacity: 1.0
}).addTo(map);
var car_icon = L.icon({
iconUrl: '/image/icon/car_icon.png',
iconSize: [24, 24], // size of the icon
iconAnchor: [27.3, 11.35], // point of the icon which will correspond to marker's location
});
my_car_ip = L.marker(my_ip, {
// icon: car_icon,
title: "",
opacity: 1.0
}).addTo(map);
window.setTimeout(getCurrentPosition_2, 1000)
}
</script>
<!--開機自啟-->
<script>
window.onload = get_data;
</script>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>RTSP Player</title>
</head>
<body>
<video id="video" width="640" height="480" autoplay></video>
<script src="https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.11.0/dist/ffmpeg-core.js"></script>
<script>
const video = document.getElementById('video');
const source = "rtsp://140.125.21.65:554/mjpeg/1";
const player = new FFmpeg.Player({
enableWorker: true,
lazyLoad: true,
video: video,
loop: true,
});
player.load(source);
</script>
</body>
</html>

View File

@ -0,0 +1,146 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='lib/bootstrap/dist/css/bootstrap.min.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static', filename='css/site.css') }}" asp-append-version="true"/>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
<script src="{{ url_for('static', filename='js/site.js') }}"></script>
<script src="{{ url_for('static', filename='lib/bootstrap/dist/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='lib/jquery/dist/jquery.min.js') }}" asp-append-version="true"></script>
</head>
<body>
<h1>IO控制</h1>
<div>
<button class="btn btn-primary" onclick="IO_1_on()">IO 1 start</button>
<button class="btn btn-primary" onclick="IO_2_on()">IO 2 start</button>
<button class="btn btn-primary" onclick="IO_3_on()">IO 3 start</button>
<button class="btn btn-primary" onclick="IO_4_on()">IO 4 start</button> <br> <br>
<button class="btn btn-primary" onclick="IO_1_off()">IO 1 close</button>
<button class="btn btn-primary" onclick="IO_2_off()">IO 2 close</button>
<button class="btn btn-primary" onclick="IO_3_off()">IO 3 close</button>
<button class="btn btn-primary" onclick="IO_4_off()">IO 4 close</button> <br>
</div>
<script>
function IO_1_on(){
$.ajax({
type: "GET",
url: "/io_1_open",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
function IO_2_on(){
$.ajax({
type: "GET",
url: "/io_2_open",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
function IO_3_on(){
$.ajax({
type: "GET",
url: "/io_3_open",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
function IO_4_on(){
$.ajax({
type: "GET",
url: "/io_4_open",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
function IO_1_off(){
$.ajax({
type: "GET",
url: "/io_1_close",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
function IO_2_off(){
$.ajax({
type: "GET",
url: "/io_2_close",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
function IO_3_off(){
$.ajax({
type: "GET",
url: "/io_3_close",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
function IO_4_off(){
$.ajax({
type: "GET",
url: "/io_4_close",
data: {},
contentType: "application/json",
success: function (Model) {
console.log(Model)
//set_data(Model)
}
});
}
</script>
</body>
</html>

View File

@ -18,3 +18,14 @@
20240429 10:05:28 - WARNING - error=HTTPConnectionPool(host='140.125.20.183', port=7700): Max retries exceeded with url: /api/Yuntech_in_car_table (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x000001985252EE20>: Failed to establish a new connection: [WinError 10060] 連線嘗試失敗,因為連線對象有一段時間並未正確回應,或是連線建立失敗,因為連線的主機無法回應。')) 20240429 10:05:28 - WARNING - error=HTTPConnectionPool(host='140.125.20.183', port=7700): Max retries exceeded with url: /api/Yuntech_in_car_table (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x000001985252EE20>: Failed to establish a new connection: [WinError 10060] 連線嘗試失敗,因為連線對象有一段時間並未正確回應,或是連線建立失敗,因為連線的主機無法回應。'))
20240429 10:05:58 - WARNING - post_error_api 20240429 10:05:58 - WARNING - post_error_api
20240429 10:05:58 - WARNING - error=HTTPConnectionPool(host='140.125.20.183', port=7700): Max retries exceeded with url: /api/Yuntech_in_car_table (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x000001985251D3A0>: Failed to establish a new connection: [WinError 10060] 連線嘗試失敗,因為連線對象有一段時間並未正確回應,或是連線建立失敗,因為連線的主機無法回應。')) 20240429 10:05:58 - WARNING - error=HTTPConnectionPool(host='140.125.20.183', port=7700): Max retries exceeded with url: /api/Yuntech_in_car_table (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x000001985251D3A0>: Failed to establish a new connection: [WinError 10060] 連線嘗試失敗,因為連線對象有一段時間並未正確回應,或是連線建立失敗,因為連線的主機無法回應。'))
20240429 15:00:43 - INFO - Start
20240429 15:02:29 - INFO - Start
20240429 15:04:09 - INFO - Start
20240429 17:39:31 - INFO - Start
20240429 17:41:18 - INFO - Start
20240429 17:54:40 - INFO - Start
20240429 17:58:39 - INFO - Start
20240429 18:01:31 - INFO - Start
20240429 18:04:25 - INFO - Start
20240429 18:09:34 - INFO - Start
20240429 18:14:38 - INFO - Start

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB