first commit
This commit is contained in:
commit
3e2b383e87
11
app/__init__.py
Normal file
11
app/__init__.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from flask import Flask
|
||||||
|
from app.routes import main
|
||||||
|
import os
|
||||||
|
|
||||||
|
def create_app():
|
||||||
|
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
template_path = os.path.join(base_dir, '..', 'templates')
|
||||||
|
static_path = os.path.join(base_dir, '..','static')
|
||||||
|
app = Flask(__name__, template_folder=template_path, static_folder=static_path)
|
||||||
|
app.register_blueprint(main)
|
||||||
|
return app
|
||||||
BIN
app/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
app/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/apiController.cpython-313.pyc
Normal file
BIN
app/__pycache__/apiController.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/mapController.cpython-313.pyc
Normal file
BIN
app/__pycache__/mapController.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/routes.cpython-313.pyc
Normal file
BIN
app/__pycache__/routes.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/utils.cpython-313.pyc
Normal file
BIN
app/__pycache__/utils.cpython-313.pyc
Normal file
Binary file not shown.
1051
app/apiController.py
Normal file
1051
app/apiController.py
Normal file
File diff suppressed because it is too large
Load Diff
111
app/mapController.py
Normal file
111
app/mapController.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import json
|
||||||
|
from app.apiController import apiController
|
||||||
|
|
||||||
|
|
||||||
|
def swap_latlon(coords):
|
||||||
|
# return [[lon, lat] for lat, lon in coords]
|
||||||
|
# print(coords)
|
||||||
|
# return [
|
||||||
|
# [ [lon, lat] for lat, lon in ring ]
|
||||||
|
# for ring in coords
|
||||||
|
# ]
|
||||||
|
return coords
|
||||||
|
return [
|
||||||
|
[ # Polygon
|
||||||
|
[ # Ring
|
||||||
|
[lon, lat] for lat, lon in ring
|
||||||
|
] for ring in polygon
|
||||||
|
] for polygon in coords
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
#MAP DATA
|
||||||
|
#=========================================================
|
||||||
|
def fetch_geojson(conn, level, parent_code=None):
|
||||||
|
# cur = conn.cursor()
|
||||||
|
# cur.execute(f"SELECT id, kode, nama, lat, lng, path, iso FROM {table_name} WHERE id = 1 LIMIT 1")
|
||||||
|
cur = conn.cursor()
|
||||||
|
if level == 'provinsi':
|
||||||
|
old_sql = """
|
||||||
|
SELECT id, kode, nama, lat, lng,
|
||||||
|
CONCAT(
|
||||||
|
REPEAT('[', 4 - (LENGTH(path) - LENGTH(REPLACE(path, '[', '')))),
|
||||||
|
path,
|
||||||
|
REPEAT(']', 4 - (LENGTH(path) - LENGTH(REPLACE(path, ']', ''))))
|
||||||
|
) AS path
|
||||||
|
FROM wil_provinsi
|
||||||
|
"""
|
||||||
|
cur.execute(old_sql)
|
||||||
|
elif level == 'kabupaten':
|
||||||
|
cur.execute(""" SELECT id, kode, nama,lat,lng,
|
||||||
|
CONCAT(
|
||||||
|
REPEAT('[', 4 - (LENGTH(path) - LENGTH(REPLACE(path, '[', '')))),
|
||||||
|
path,
|
||||||
|
REPEAT(']', 4 - (LENGTH(path) - LENGTH(REPLACE(path, ']', ''))))
|
||||||
|
) AS path
|
||||||
|
FROM wil_kabupatenkota WHERE provinsi_id = %s""", (parent_code,))
|
||||||
|
elif level == 'kecamatan':
|
||||||
|
cur.execute("""
|
||||||
|
SELECT id, kode, nama,lat,lng,
|
||||||
|
CONCAT(
|
||||||
|
REPEAT('[', 4 - (LENGTH(path) - LENGTH(REPLACE(path, '[', '')))),
|
||||||
|
path,
|
||||||
|
REPEAT(']', 4 - (LENGTH(path) - LENGTH(REPLACE(path, ']', ''))))
|
||||||
|
) AS path
|
||||||
|
FROM wil_kecamatan WHERE kabupatenkota_id = %s""", (parent_code,))
|
||||||
|
elif level == 'desa':
|
||||||
|
cur.execute("""
|
||||||
|
SELECT id, kode, nama, null as lat, null as lng,
|
||||||
|
CONCAT(
|
||||||
|
REPEAT('[', 4 - (LENGTH(path) - LENGTH(REPLACE(path, '[', '')))),
|
||||||
|
path,
|
||||||
|
REPEAT(']', 4 - (LENGTH(path) - LENGTH(REPLACE(path, ']', ''))))
|
||||||
|
) AS path
|
||||||
|
FROM wil_desa WHERE kecamatan_id = %s""", (parent_code,))
|
||||||
|
else:
|
||||||
|
return {"type": "FeatureCollection", "features": []}
|
||||||
|
features = []
|
||||||
|
|
||||||
|
for row in cur.fetchall():
|
||||||
|
path = row[5]
|
||||||
|
# path = swap_latlon(path)
|
||||||
|
# if not path:
|
||||||
|
# continue
|
||||||
|
# geometry = {
|
||||||
|
# "type": "Polygon",
|
||||||
|
# "coordinates": json.loads(path)
|
||||||
|
# }
|
||||||
|
|
||||||
|
#Multi poligons
|
||||||
|
try:
|
||||||
|
parsed_path = json.loads(path)
|
||||||
|
corrected_path = swap_latlon(parsed_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error parsing path for row {row[0]}: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not corrected_path:
|
||||||
|
continue
|
||||||
|
|
||||||
|
geometry = {
|
||||||
|
"type": "MultiPolygon", # karena bentuk datamu seperti itu
|
||||||
|
"coordinates": corrected_path
|
||||||
|
}
|
||||||
|
|
||||||
|
feature = {
|
||||||
|
"type": "Feature",
|
||||||
|
"geometry": geometry,
|
||||||
|
"properties": {
|
||||||
|
"id": row[0],
|
||||||
|
"kode": row[1],
|
||||||
|
"nama": row[2],
|
||||||
|
"lat": row[3],
|
||||||
|
"lng": row[4]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
features.append(feature)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": features
|
||||||
|
}
|
||||||
285
app/routes.py
Normal file
285
app/routes.py
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
from flask import Blueprint, jsonify, render_template
|
||||||
|
import psycopg2
|
||||||
|
from app import mapController
|
||||||
|
from app.apiController import apiController
|
||||||
|
from app.utils import toRupiah
|
||||||
|
import mysql.connector
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
main = Blueprint('main', __name__)
|
||||||
|
|
||||||
|
# conn = mysql.connector.connect(
|
||||||
|
# host="192.168.91.102",
|
||||||
|
# database="dbwarehouse",
|
||||||
|
# user="dwhadmin",
|
||||||
|
# password="K3m3nd3s4@2025"
|
||||||
|
# )
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def get_connection():
|
||||||
|
conn = None
|
||||||
|
try:
|
||||||
|
conn = mysql.connector.connect(
|
||||||
|
# 192.168.91.102
|
||||||
|
host="localhost",
|
||||||
|
database="dbwarehouse",
|
||||||
|
# dwhadmin
|
||||||
|
user="root",
|
||||||
|
# K3m3nd3s4@2025
|
||||||
|
password="asalada123"
|
||||||
|
)
|
||||||
|
yield conn
|
||||||
|
finally:
|
||||||
|
if conn is not None and conn.is_connected():
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
#========================================================
|
||||||
|
# MAIN ROUTE
|
||||||
|
#========================================================
|
||||||
|
@main.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@main.route("/geojson/provinsi")
|
||||||
|
def get_provinsi():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = mapController.fetch_geojson(conn,'provinsi')
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route("/geojson/kabupaten/<kode_provinsi>")
|
||||||
|
def get_kabupaten(kode_provinsi):
|
||||||
|
with get_connection() as conn:
|
||||||
|
print("PRovinsi kode: ", kode_provinsi)
|
||||||
|
data = mapController.fetch_geojson(conn,'kabupaten', kode_provinsi)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route("/geojson/kecamatan/<kode_kabupaten>")
|
||||||
|
def get_kecamatan(kode_kabupaten):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = mapController.fetch_geojson(conn,'kecamatan', kode_kabupaten)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route("/geojson/desa/<kode_kecamatan>")
|
||||||
|
def get_desa(kode_kecamatan):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = mapController.fetch_geojson(conn,'desa', kode_kecamatan)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#=========================================================
|
||||||
|
# API DATA
|
||||||
|
#=============================================================
|
||||||
|
@main.route('/api/desa/total-dana-desa')
|
||||||
|
def get_total_dd():
|
||||||
|
with get_connection() as conn:
|
||||||
|
datas = apiController.getTotalPersentaseSerapan(conn)
|
||||||
|
data = datas['jumlah_per_m']
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route("/api/desa/total-serapan-dana")
|
||||||
|
def get_total_Serapan():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getTotalPersentaseSerapan(conn)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route('/api/geojson/<level>')
|
||||||
|
def get_geojson(level):
|
||||||
|
print(level)
|
||||||
|
allowed = ['wil_provinsi', 'wil_kabupaten_kota', 'wil_kecamatan', 'wil_kelurahan_desa']
|
||||||
|
if level not in allowed:
|
||||||
|
return jsonify({"error": "Invalid level"}), 400
|
||||||
|
|
||||||
|
geojson_data = mapController.fetch_geojson(conn,level)
|
||||||
|
return jsonify(geojson_data)
|
||||||
|
|
||||||
|
|
||||||
|
#Informasi desa per provinsi
|
||||||
|
@main.route('/api/status-provinsi/<kode_provinsi>')
|
||||||
|
def get_status_provinsi(kode_provinsi):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getStatusProvinsi(conn,kode_provinsi)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi desa per kabupaten/kota
|
||||||
|
@main.route('/api/status-kabupatenkota/<kode_prov>/<kode_kabkota>')
|
||||||
|
def get_status_kabkota(kode_prov, kode_kabkota):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getStatusKabkota(conn,kode_prov, kode_kabkota)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi desa per kecamatan
|
||||||
|
@main.route('/api/status-kecamatan/<kode_provinsi>/<kode_kabupatenkota>/<kode_kecamatan>')
|
||||||
|
def get_status_kecamatan(kode_provinsi, kode_kabupatenkota, kode_kecamatan):
|
||||||
|
print(kode_provinsi, kode_kabupatenkota, kode_kecamatan)
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getStatusKecamatan(conn,kode_provinsi, kode_kabupatenkota, kode_kecamatan)
|
||||||
|
data = jsonify(data)
|
||||||
|
return data
|
||||||
|
@main.route("/api/status-bumdes")
|
||||||
|
def get_status_bumdes():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getBumdes(conn)
|
||||||
|
return jsonify(data[0])
|
||||||
|
|
||||||
|
#informasi bumdes Bersama
|
||||||
|
@main.route("/api/status-bumdes-bersama")
|
||||||
|
def get_status_bumdes_bersma():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getBumdes(conn)
|
||||||
|
return jsonify(data[1])
|
||||||
|
|
||||||
|
#informasi pendamping
|
||||||
|
@main.route('/api/pendamping-desa')
|
||||||
|
def get_pendamping():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getPendamping(conn)
|
||||||
|
return jsonify(data[1])
|
||||||
|
#informasi pendamping per desa
|
||||||
|
@main.route('/api/pendamping-per-desa')
|
||||||
|
def get_pendamping_perdesa():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getPendampingPerDesa(conn)
|
||||||
|
return jsonify(data[0])
|
||||||
|
|
||||||
|
#=======================================================================
|
||||||
|
#=======================================================================
|
||||||
|
#informasi Koperasi
|
||||||
|
@main.route('/api/provinsi/koperasi/<kode_prov>')
|
||||||
|
def get_koperasi_by_provinsi(kode_prov):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getDesaDenganAtauTanpaKopmerKab(conn, kode_prov)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route('/api/provinsi/pendamping/<kode_prov>')
|
||||||
|
def get_pendamping_per_provinsi(kode_prov):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getPendampingPerProv(conn, kode_prov)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi bumdes per provinsi
|
||||||
|
@main.route("/api/provinsi/bumdes/<kode_provinsi>")
|
||||||
|
def get_status_bumdes_prov(kode_provinsi):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getBumdesProv(conn,kode_provinsi)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi serapan per provinsi
|
||||||
|
@main.route("/api/provinsi/serapan/<kode_provinsi>")
|
||||||
|
def get_provinsi_serapan(kode_provinsi):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getTotalSerapanProv(conn,kode_provinsi)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#=======================================================================
|
||||||
|
#=======================================================================
|
||||||
|
#informasi Koperasi
|
||||||
|
@main.route('/api/kabkota/koperasi/<kode_kabkota>')
|
||||||
|
def get_koperasi_by_kabkota(kode_kabkota):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getDesaDenganAtauTanpaKopmerKab(conn, kode_kabkota)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route('/api/kabkota/pendamping/<kode_kabkota>')
|
||||||
|
def get_pendamping_per_kabkota(kode_kabkota):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getPendampingPerKab(conn, kode_kabkota)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi bumdes
|
||||||
|
@main.route("/api/kabkota/bumdes/<kode_kabkota>")
|
||||||
|
def get_status_bumdes_kabkota(kode_kabkota):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getBumdesKab(conn,kode_kabkota)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi serapan
|
||||||
|
@main.route("/api/kabkota/serapan/<kode_kabkota>")
|
||||||
|
def get_kabkota_serapan(kode_kabkota):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getTotalSerapanKab(conn,kode_kabkota)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#=======================================================================
|
||||||
|
#=======================================================================
|
||||||
|
#informasi Koperasi
|
||||||
|
@main.route('/api/kecamatan/koperasi/<kode_kecamatan>')
|
||||||
|
def get_koperasi_by_kecamatan(kode_kecamatan):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getDesaDenganAtauTanpaKopmerKec(conn, kode_kecamatan)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route('/api/kecamatan/pendamping/<kode_kecamatan>')
|
||||||
|
def get_pendamping_per_kecamatan(kode_kecamatan):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getPendampingPerKec(conn, kode_kecamatan)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi bumdes
|
||||||
|
@main.route("/api/kecamatan/bumdes/<kode_kecamatan>")
|
||||||
|
def get_status_bumdes_kecamatan(kode_kecamatan):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getBumdesKec(conn,kode_kecamatan)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi serapan
|
||||||
|
@main.route("/api/kecamatan/serapan/<kode_kecamatan>")
|
||||||
|
def get_kecamatan_serapan(kode_kecamatan):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getTotalSerapanKec(conn,kode_kecamatan)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#=======================================================================
|
||||||
|
#=======================================================================
|
||||||
|
#informasi Koperasi
|
||||||
|
@main.route('/api/desa/status/<kode_prov>/<kode_kabkota>/<kode_kecamatan>/<kode_desa>')
|
||||||
|
def get_status_by_desa(kode_prov, kode_kabkota, kode_kecamatan, kode_desa):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getStatusDesaByDesa(conn, kode_prov, kode_kabkota, kode_kecamatan, kode_desa)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route('/api/desa/koperasi/<kode_desa>')
|
||||||
|
def get_koperasi_by_desa(kode_desa):
|
||||||
|
data = apiController.getDesaDenganAtauTanpaKopmerDesa(conn, kode_desa)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route('/api/desa/pendamping/<kode_desa>')
|
||||||
|
def get_pendamping_per_desa(kode_desa):
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.getPendampingPerDesa(conn, kode_desa)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi bumdes
|
||||||
|
@main.route("/api/desa/bumdes/<kode_desa>")
|
||||||
|
def get_status_bumdes_desa(kode_desa):
|
||||||
|
data = apiController.getBumdesDesa(conn,kode_desa)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#informasi serapan
|
||||||
|
@main.route("/api/desa/serapan/<kode_desa>")
|
||||||
|
def get_pdesa_serapan(kode_desa):
|
||||||
|
data = apiController.getTotalSerapanDesa(conn,kode_desa)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
#==================
|
||||||
|
# MASTER
|
||||||
|
#===============
|
||||||
|
|
||||||
|
@main.route('/app/master/provinsi')
|
||||||
|
def get_master_provinsi():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.provinsi(conn)
|
||||||
|
return data
|
||||||
|
|
||||||
|
@main.route('/api/master/kabkota')
|
||||||
|
def get_master_kabkota():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.kabkota
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@main.route('/api/master/kecamatan')
|
||||||
|
def get_master_kecamatan():
|
||||||
|
with get_connection() as conn:
|
||||||
|
data = apiController.kecamatan(conn)
|
||||||
|
return jsonify(data)
|
||||||
3
app/utils.py
Normal file
3
app/utils.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from babel.numbers import format_currency
|
||||||
|
def toRupiah(money):
|
||||||
|
return format_currency(money, 'IDR', locale='id_ID')
|
||||||
15
run.py
Normal file
15
run.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from app import create_app
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
|
|
||||||
|
def swap_latlon(coords):
|
||||||
|
return [
|
||||||
|
[ # Polygon
|
||||||
|
[ # Ring
|
||||||
|
[lon, lat] for lat, lon in ring
|
||||||
|
] for ring in polygon
|
||||||
|
] for polygon in coords
|
||||||
|
]
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(debug=True, port=5000)
|
||||||
BIN
static/css/.DS_Store
vendored
Normal file
BIN
static/css/.DS_Store
vendored
Normal file
Binary file not shown.
1912
static/css/bootstrap-grid.css
vendored
Normal file
1912
static/css/bootstrap-grid.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
static/css/bootstrap-grid.css.map
Normal file
1
static/css/bootstrap-grid.css.map
Normal file
File diff suppressed because one or more lines are too long
7
static/css/bootstrap-grid.min.css
vendored
Normal file
7
static/css/bootstrap-grid.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/css/bootstrap-grid.min.css.map
Normal file
1
static/css/bootstrap-grid.min.css.map
Normal file
File diff suppressed because one or more lines are too long
331
static/css/bootstrap-reboot.css
vendored
Normal file
331
static/css/bootstrap-reboot.css
vendored
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2018 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2018 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@-ms-viewport {
|
||||||
|
width: device-width;
|
||||||
|
}
|
||||||
|
|
||||||
|
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tabindex="-1"]:focus {
|
||||||
|
outline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr[title],
|
||||||
|
abbr[data-original-title] {
|
||||||
|
text-decoration: underline;
|
||||||
|
-webkit-text-decoration: underline dotted;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
cursor: help;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
address {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-style: normal;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
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: .5rem;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
position: relative;
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #007bff;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: transparent;
|
||||||
|
-webkit-text-decoration-skip: objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #0056b3;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]):focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
overflow: auto;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: middle;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
color: #6c757d;
|
||||||
|
text-align: left;
|
||||||
|
caption-side: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus {
|
||||||
|
outline: 1px dotted;
|
||||||
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
optgroup,
|
||||||
|
textarea {
|
||||||
|
margin: 0;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
html [type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
padding: 0;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="date"],
|
||||||
|
input[type="time"],
|
||||||
|
input[type="datetime-local"],
|
||||||
|
input[type="month"] {
|
||||||
|
-webkit-appearance: listbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
outline-offset: -2px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-cancel-button,
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
font: inherit;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
output {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||||
1
static/css/bootstrap-reboot.css.map
Normal file
1
static/css/bootstrap-reboot.css.map
Normal file
File diff suppressed because one or more lines are too long
8
static/css/bootstrap-reboot.min.css
vendored
Normal file
8
static/css/bootstrap-reboot.min.css
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2018 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2018 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}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}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
||||||
1
static/css/bootstrap-reboot.min.css.map
Normal file
1
static/css/bootstrap-reboot.min.css.map
Normal file
File diff suppressed because one or more lines are too long
9030
static/css/bootstrap.css
vendored
Normal file
9030
static/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
static/css/bootstrap.css.map
Normal file
1
static/css/bootstrap.css.map
Normal file
File diff suppressed because one or more lines are too long
7
static/css/bootstrap.min.css
vendored
Normal file
7
static/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/css/bootstrap.min.css.map
Normal file
1
static/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
595
static/css/select2.css
Normal file
595
static/css/select2.css
Normal file
@ -0,0 +1,595 @@
|
|||||||
|
.select2-container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.select2-container .select2-selection--single {
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
height: 28px;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
.select2-container .select2-selection--single .select2-selection__rendered {
|
||||||
|
display: block;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.select2-container .select2-selection--single .select2-selection__clear {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.select2-container[dir=rtl] .select2-selection--single .select2-selection__rendered {
|
||||||
|
padding-right: 8px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.select2-container .select2-selection--multiple {
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
min-height: 32px;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||||
|
display: inline;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.select2-container .select2-selection--multiple .select2-selection__clear {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.select2-container .select2-search--inline .select2-search__field {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: none;
|
||||||
|
font-size: 100%;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
padding: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
resize: none;
|
||||||
|
height: 18px;
|
||||||
|
vertical-align: bottom;
|
||||||
|
font-family: sans-serif;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-dropdown {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: -100000px;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1051;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-results {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-results__options {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-results__option {
|
||||||
|
padding: 6px;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-results__option--selectable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--open .select2-dropdown {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--open .select2-dropdown--above {
|
||||||
|
border-bottom: none;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--open .select2-dropdown--below {
|
||||||
|
border-top: none;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-search--dropdown {
|
||||||
|
display: block;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
.select2-search--dropdown .select2-search__field {
|
||||||
|
padding: 4px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
.select2-search--dropdown.select2-search--hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-close-mask {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
min-height: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 99;
|
||||||
|
background-color: #fff;
|
||||||
|
filter: alpha(opacity=0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-hidden-accessible {
|
||||||
|
border: 0 !important;
|
||||||
|
clip: rect(0 0 0 0) !important;
|
||||||
|
-webkit-clip-path: inset(50%) !important;
|
||||||
|
clip-path: inset(50%) !important;
|
||||||
|
height: 1px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
position: absolute !important;
|
||||||
|
width: 1px !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--default .select2-selection--single {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||||
|
color: #444;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--single .select2-selection__clear {
|
||||||
|
cursor: pointer;
|
||||||
|
float: right;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 26px;
|
||||||
|
margin-right: 20px;
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||||
|
height: 26px;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 1px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||||
|
border-color: #888 transparent transparent transparent;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 5px 4px 0 4px;
|
||||||
|
height: 0;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -4px;
|
||||||
|
margin-top: -2px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__clear {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__arrow {
|
||||||
|
left: 1px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--disabled .select2-selection--single {
|
||||||
|
background-color: #eee;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||||
|
border-color: transparent transparent #888 transparent;
|
||||||
|
border-width: 0 4px 5px 4px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: text;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple.select2-selection--clearable {
|
||||||
|
padding-right: 25px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple .select2-selection__clear {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||||
|
background-color: #e4e4e4;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
vertical-align: bottom;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple .select2-selection__choice__display {
|
||||||
|
cursor: default;
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
border-right: 1px solid #aaa;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 4px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover, .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:focus {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
color: #333;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice__display {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove {
|
||||||
|
border-left: 1px solid #aaa;
|
||||||
|
border-right: none;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__clear {
|
||||||
|
float: left;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--focus .select2-selection--multiple {
|
||||||
|
border: solid black 1px;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--disabled .select2-selection--multiple {
|
||||||
|
background-color: #eee;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-search--inline .select2-search__field {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results > .select2-results__options {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option .select2-results__option {
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option .select2-results__option .select2-results__group {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option .select2-results__option .select2-results__option {
|
||||||
|
margin-left: -1em;
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||||
|
margin-left: -2em;
|
||||||
|
padding-left: 3em;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||||
|
margin-left: -3em;
|
||||||
|
padding-left: 4em;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||||
|
margin-left: -4em;
|
||||||
|
padding-left: 5em;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||||
|
margin-left: -5em;
|
||||||
|
padding-left: 6em;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option--group {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option--disabled {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option--selected {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
|
||||||
|
background-color: #5897fb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__group {
|
||||||
|
cursor: default;
|
||||||
|
display: block;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--classic .select2-selection--single {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: 0;
|
||||||
|
background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||||
|
background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||||
|
background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF", endColorstr="#FFEEEEEE", GradientType=0);
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--single:focus {
|
||||||
|
border: 1px solid #5897fb;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--single .select2-selection__rendered {
|
||||||
|
color: #444;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--single .select2-selection__clear {
|
||||||
|
cursor: pointer;
|
||||||
|
float: right;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 26px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--single .select2-selection__arrow {
|
||||||
|
background-color: #ddd;
|
||||||
|
border: none;
|
||||||
|
border-left: 1px solid #aaa;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
height: 26px;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 1px;
|
||||||
|
width: 20px;
|
||||||
|
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||||
|
background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||||
|
background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE", endColorstr="#FFCCCCCC", GradientType=0);
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--single .select2-selection__arrow b {
|
||||||
|
border-color: #888 transparent transparent transparent;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 5px 4px 0 4px;
|
||||||
|
height: 0;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -4px;
|
||||||
|
margin-top: -2px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__clear {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__arrow {
|
||||||
|
border: none;
|
||||||
|
border-right: 1px solid #aaa;
|
||||||
|
border-radius: 0;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
left: 1px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open .select2-selection--single {
|
||||||
|
border: 1px solid #5897fb;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||||
|
border-color: transparent transparent #888 transparent;
|
||||||
|
border-width: 0 4px 5px 4px;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
|
||||||
|
border-top: none;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||||
|
background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||||
|
background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF", endColorstr="#FFEEEEEE", GradientType=0);
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
|
||||||
|
border-bottom: none;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||||
|
background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||||
|
background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE", endColorstr="#FFFFFFFF", GradientType=0);
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--multiple {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: text;
|
||||||
|
outline: 0;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--multiple:focus {
|
||||||
|
border: 1px solid #5897fb;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--multiple .select2-selection__clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--multiple .select2-selection__choice {
|
||||||
|
background-color: #e4e4e4;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--multiple .select2-selection__choice__display {
|
||||||
|
cursor: default;
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
color: #888;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||||
|
color: #555;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice__display {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open .select2-selection--multiple {
|
||||||
|
border: 1px solid #5897fb;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||||
|
border-top: none;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||||
|
border-bottom: none;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-search--dropdown .select2-search__field {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-search--inline .select2-search__field {
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-dropdown {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-dropdown--above {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-dropdown--below {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-results > .select2-results__options {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-results__option--group {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-results__option--disabled {
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-results__option--highlighted.select2-results__option--selectable {
|
||||||
|
background-color: #3875d7;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.select2-container--classic .select2-results__group {
|
||||||
|
cursor: default;
|
||||||
|
display: block;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
.select2-container--classic.select2-container--open .select2-dropdown {
|
||||||
|
border-color: #5897fb;
|
||||||
|
}
|
||||||
1
static/css/select2.min.css
vendored
Normal file
1
static/css/select2.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6461
static/js/bootstrap.bundle.js
vendored
Normal file
6461
static/js/bootstrap.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
static/js/bootstrap.bundle.js.map
Normal file
1
static/js/bootstrap.bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
7
static/js/bootstrap.bundle.min.js
vendored
Normal file
7
static/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/js/bootstrap.bundle.min.js.map
Normal file
1
static/js/bootstrap.bundle.min.js.map
Normal file
File diff suppressed because one or more lines are too long
3944
static/js/bootstrap.js
vendored
Normal file
3944
static/js/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
static/js/bootstrap.js.map
Normal file
1
static/js/bootstrap.js.map
Normal file
File diff suppressed because one or more lines are too long
7
static/js/bootstrap.min.js
vendored
Normal file
7
static/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/js/bootstrap.min.js.map
Normal file
1
static/js/bootstrap.min.js.map
Normal file
File diff suppressed because one or more lines are too long
10716
static/js/jquery-3.7.1.js
vendored
Normal file
10716
static/js/jquery-3.7.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
static/js/select2.full.min.js
vendored
Normal file
2
static/js/select2.full.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
static/js/select2.min.js
vendored
Normal file
2
static/js/select2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
196
static/responsive.css
Normal file
196
static/responsive.css
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/* responsive.css*/
|
||||||
|
|
||||||
|
@media screen and (max-width: 950px) {
|
||||||
|
.nav-img {
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option {
|
||||||
|
gap: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option h3 {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-topic-heading,
|
||||||
|
.item1,
|
||||||
|
.items {
|
||||||
|
width: 800px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 850px) {
|
||||||
|
.nav-img {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option {
|
||||||
|
gap: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option h3 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-topic-heading,
|
||||||
|
.item1,
|
||||||
|
.items {
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcontainer {
|
||||||
|
width: 100vw;
|
||||||
|
position: absolute;
|
||||||
|
transition: all 0.6s ease-in-out;
|
||||||
|
top: 0;
|
||||||
|
left: -100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navclose {
|
||||||
|
left: 00px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
padding: 40px 30px 30px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar2 {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
margin: 0 0 40px 0;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar2 input {
|
||||||
|
width: 250px;
|
||||||
|
height: 42px;
|
||||||
|
border-radius: 50px 0 0 50px;
|
||||||
|
background-color: var(--background-color3);
|
||||||
|
padding: 0 20px;
|
||||||
|
font-size: 15px;
|
||||||
|
border: 2px solid var(--secondary-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 490px) {
|
||||||
|
.message {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logosec {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuicn {
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-img {
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option {
|
||||||
|
gap: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option h3 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-upper-options {
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-Articles {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-topic-heading,
|
||||||
|
.item1,
|
||||||
|
.items {
|
||||||
|
width: 550px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 400px) {
|
||||||
|
.recent-Articles {
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view {
|
||||||
|
width: 60px;
|
||||||
|
font-size: 10px;
|
||||||
|
height: 27px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-header {
|
||||||
|
height: 60px;
|
||||||
|
padding: 10px 10px 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbtn img {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 320px) {
|
||||||
|
.recent-Articles {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view {
|
||||||
|
width: 50px;
|
||||||
|
font-size: 8px;
|
||||||
|
height: 27px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-header {
|
||||||
|
height: 60px;
|
||||||
|
padding: 10px 5px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-op {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-op-nextlvl {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-topic-heading,
|
||||||
|
.item1,
|
||||||
|
.items {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-tag {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbtn {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar2 input {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
static/script.js
Normal file
8
static/script.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
//index.js
|
||||||
|
|
||||||
|
// let menuicn = document.querySelector(".menuicn");
|
||||||
|
// let nav = document.querySelector(".navcontainer");
|
||||||
|
|
||||||
|
// menuicn.addEventListener("click", () => {
|
||||||
|
// nav.classList.toggle("navclose");
|
||||||
|
// })
|
||||||
401
static/style.css
Normal file
401
static/style.css
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
/*style.css*/
|
||||||
|
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background-color1: #fafaff;
|
||||||
|
--background-color2: #ffffff;
|
||||||
|
--background-color3: #ededed;
|
||||||
|
--background-color4: #cad7fda4;
|
||||||
|
--primary-color: #4b49ac;
|
||||||
|
--secondary-color: #0c007d;
|
||||||
|
--Border-color: #3f0097;
|
||||||
|
--one-use-color: #3f0097;
|
||||||
|
--two-use-color: #5500cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--background-color4);
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
height: 70px;
|
||||||
|
width: 100vw;
|
||||||
|
padding: 0 30px;
|
||||||
|
background-color: var(--background-color1);
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 1px 1px 15px rgba(161, 182, 253, 0.825);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 27px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgb(47, 141, 70);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icn {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuicn {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar,
|
||||||
|
.message,
|
||||||
|
.logosec {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar2 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logosec {
|
||||||
|
gap: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar input {
|
||||||
|
width: 250px;
|
||||||
|
height: 42px;
|
||||||
|
border-radius: 50px 0 0 50px;
|
||||||
|
background-color: var(--background-color3);
|
||||||
|
padding: 0 20px;
|
||||||
|
font-size: 15px;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbtn {
|
||||||
|
width: 50px;
|
||||||
|
height: 42px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 0px 50px 50px 0px;
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
gap: 40px;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
height: 7px;
|
||||||
|
width: 7px;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #fa7bb4;
|
||||||
|
border-radius: 50%;
|
||||||
|
left: 19px;
|
||||||
|
top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dp {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
background-color: #626262;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100vw;
|
||||||
|
position: relative;
|
||||||
|
top: 70px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dpicn {
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
height: calc(100vh - 70px);
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 40px 30px 30px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main::-webkit-scrollbar-thumb {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to bottom, rgb(0, 0, 85), rgb(0, 0, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
.main::-webkit-scrollbar {
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main::-webkit-scrollbar-track {
|
||||||
|
background-color: #9e9e9eb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
min-height: 91vh;
|
||||||
|
width: 250px;
|
||||||
|
background-color: var(--background-color2);
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 00;
|
||||||
|
box-shadow: 1px 1px 10px rgba(198, 189, 248, 0.825);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 30px 0 20px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcontainer {
|
||||||
|
height: calc(100vh - 70px);
|
||||||
|
width: 250px;
|
||||||
|
position: relative;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: all 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcontainer::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navclose {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option {
|
||||||
|
width: 250px;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 30px 0 20px;
|
||||||
|
gap: 20px;
|
||||||
|
transition: all 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-option:hover {
|
||||||
|
border-left: 5px solid #a2a2a2;
|
||||||
|
background-color: #dadada;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-img {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-upper-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option1 {
|
||||||
|
border-left: 5px solid #010058af;
|
||||||
|
background-color: var(--Border-color);
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option1:hover {
|
||||||
|
border-left: 5px solid #010058af;
|
||||||
|
background-color: var(--Border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
height: 130px;
|
||||||
|
width: 430px;
|
||||||
|
border-radius: 20px;
|
||||||
|
box-shadow: 3px 3px 10px rgba(0, 30, 87, 0.751);
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:hover {
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:nth-child(1) {
|
||||||
|
background-color: var(--one-use-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:nth-child(2) {
|
||||||
|
background-color: var(--two-use-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:nth-child(3) {
|
||||||
|
background-color: var(--one-use-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:nth-child(4) {
|
||||||
|
background-color: var(--two-use-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box img {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .text {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topic {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topic-heading {
|
||||||
|
font-size: 30px;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-container {
|
||||||
|
min-height: 90vh;
|
||||||
|
/*max-width: 1200px; */
|
||||||
|
margin: 10px auto 0px auto;
|
||||||
|
background-color:rgb(188, 188, 188);
|
||||||
|
border-radius: 30px;
|
||||||
|
box-shadow: 3px 3px 10px rgb(188, 188, 188);
|
||||||
|
padding: 0px 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-header {
|
||||||
|
height: 130px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20px 20px 10px 20px;
|
||||||
|
border-bottom: 2px solid rgba(0, 20, 151, 0.59);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header_container {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-container{
|
||||||
|
flex: 3; /* 3 bagian dari 4 */
|
||||||
|
background-color: lightblue;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side_container {
|
||||||
|
flex: 1; /* 1 bagian dari 4 */
|
||||||
|
background-color: rgb(226, 226, 226);
|
||||||
|
padding: 20px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-Articles {
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #5500cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view {
|
||||||
|
height: 35px;
|
||||||
|
width: 90px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #5500cb;
|
||||||
|
color: white;
|
||||||
|
font-size: 15px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-body {
|
||||||
|
max-width: 1160px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-topic-heading,
|
||||||
|
.item1 {
|
||||||
|
width: 1120px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-op {
|
||||||
|
font-size: 18px;
|
||||||
|
letter-spacing: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items {
|
||||||
|
width: 1120px;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item1 {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-op-nextlvl {
|
||||||
|
font-size: 14px;
|
||||||
|
letter-spacing: 0px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-tag {
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: rgb(0, 177, 0);
|
||||||
|
color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#map {
|
||||||
|
/* position: absolute; */
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
85
templates/flaskmap.html
Normal file
85
templates/flaskmap.html
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Peta Wilayah</title>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
||||||
|
<style>#map { height: 100vh; }</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="map"></div>
|
||||||
|
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
|
||||||
|
<script>
|
||||||
|
const map = L.map('map').setView([4.2, 96.9], 7);
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
|
||||||
|
|
||||||
|
// Ganti endpoint berdasarkan level: wil_provinsi, wil_kabupaten_kota, dll
|
||||||
|
// fetch('http://localhost:5000/api/geojson/wil_provinsi')
|
||||||
|
// .then(res => res.json())
|
||||||
|
// .then(data => {
|
||||||
|
// L.geoJSON(data, {
|
||||||
|
// style: { color: 'blue' },
|
||||||
|
// onEachFeature: function (feature, layer) {
|
||||||
|
// const p = feature.properties;
|
||||||
|
// layer.bindPopup(`<strong>${p.nama}</strong><br>Kode: ${p.kode}`);
|
||||||
|
// }
|
||||||
|
// }).addTo(map);
|
||||||
|
// });
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
let currentLayer = null;
|
||||||
|
|
||||||
|
function loadLayer(url, onClickCallback) {
|
||||||
|
fetch(url)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (currentLayer) {
|
||||||
|
map.removeLayer(currentLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLayer = L.geoJSON(data, {
|
||||||
|
style: { color: "blue", weight: 2 },
|
||||||
|
onEachFeature: function (feature, layer) {
|
||||||
|
let clickTimer = null;
|
||||||
|
layer.on('click', function (e) {
|
||||||
|
let kode = feature.properties.id;
|
||||||
|
// onClickCallback(kode);
|
||||||
|
if (clickTimer) {
|
||||||
|
// Double click detected
|
||||||
|
clearTimeout(clickTimer);
|
||||||
|
clickTimer = null;
|
||||||
|
|
||||||
|
// Aksi double click → Pindah layer
|
||||||
|
let kode = feature.properties.id;
|
||||||
|
onClickCallback(kode);
|
||||||
|
} else {
|
||||||
|
// Single click → Tampilkan popup
|
||||||
|
clickTimer = setTimeout(() => {
|
||||||
|
clickTimer = null;
|
||||||
|
layer.bindPopup(feature.properties.nama).openPopup(e.latlng);
|
||||||
|
}, 250); // waktu tunggu untuk deteksi double click
|
||||||
|
layer.bindPopup(feature.properties.nama);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// layer.bindPopup(feature.properties.nama);
|
||||||
|
}
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
map.fitBounds(currentLayer.getBounds());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load provinsi Aceh awal
|
||||||
|
loadLayer('/geojson/provinsi', function (kode_provinsi) {
|
||||||
|
loadLayer(`/geojson/kabupaten/${kode_provinsi}`, function (kode_kabupaten) {
|
||||||
|
loadLayer(`/geojson/kecamatan/${kode_kabupaten}`, function (kode_kecamatan) {
|
||||||
|
loadLayer(`/geojson/desa/${kode_kecamatan}`, function () {
|
||||||
|
// Desa tidak turun level lagi
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
735
templates/index.html
Normal file
735
templates/index.html
Normal file
@ -0,0 +1,735 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Peta Wilayah</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" />
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" />
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/select2.min.css') }}" />
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='responsive.css') }}" />
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
||||||
|
<style>
|
||||||
|
.select2-selection__arrow {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="main-container">
|
||||||
|
|
||||||
|
<div class="main">
|
||||||
|
<div class="searchbar2">
|
||||||
|
<input type="text" name="" id="" placeholder="Search" />
|
||||||
|
<div class="searchbtn">
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210180758/Untitled-design-(28).png"
|
||||||
|
class="icn srchicn" alt="search-button" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="box-container">
|
||||||
|
<div class="box box1">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading">60.5k</h2>
|
||||||
|
<h2 class="topic">Article Views</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(31).png"
|
||||||
|
alt="Views" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box box2">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading">150</h2>
|
||||||
|
<h2 class="topic">Likes</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185030/14.png" alt="likes" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box box3">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading">320</h2>
|
||||||
|
<h2 class="topic">Comments</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(32).png"
|
||||||
|
alt="comments" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box box4">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading">70</h2>
|
||||||
|
<h2 class="topic">Published</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185029/13.png"
|
||||||
|
alt="published" />
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<div class="report-container">
|
||||||
|
<div class="report-header">
|
||||||
|
<!-- <h1 class="recent-Articles">Recent Articles</h1>
|
||||||
|
<button class="view">View All</button> -->
|
||||||
|
<div class="box-container">
|
||||||
|
<div class="box box1">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading" id="tot_dd">Total Dana Desa</h2>
|
||||||
|
<h2 class="topic">Total Dana Desa</h2>
|
||||||
|
<h2></h2>
|
||||||
|
</div>
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(31).png"
|
||||||
|
alt="Views" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box box2">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading" id="tot_sr">150</h2>
|
||||||
|
<h2 class="topic">Total Serapan</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185030/14.png" alt="likes" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box box3">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading" id="pr_sr">320</h2>
|
||||||
|
<h2 class="topic">Persentase Serapan</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(32).png"
|
||||||
|
alt="comments" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box box4">
|
||||||
|
<div class="text">
|
||||||
|
<h2 class="topic-heading">70</h2>
|
||||||
|
<h2 class="topic">Published</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185029/13.png"
|
||||||
|
alt="published" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="header_container">
|
||||||
|
<div class="map-container" id="map"></div>
|
||||||
|
<div class="side_container" style="height:100%">
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" style="width: 150px;">
|
||||||
|
Provinsi
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<select class="form-control select2 border border-primary" name="provinsiDropdown" id="provinsiDropdown"
|
||||||
|
data-placeholder="Provinsi ......">
|
||||||
|
<option></option>
|
||||||
|
<option value="1">Option 1</option>
|
||||||
|
<option value="2">Option 2</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" style="width: 150px;">
|
||||||
|
Kabupaten/Kota
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<select class="form-control select2" name="kabkotaDropdown" id="kabkotaDropdown"
|
||||||
|
data-placeholder="Kabupaten/Kota ....." >
|
||||||
|
<option></option>
|
||||||
|
<option value="1">Option 1</option>
|
||||||
|
<option value="2">Option 2</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" style="width: 150px;">
|
||||||
|
Kecamatan
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<select class="form-control select2" name="kecamatanDropdown" id="kecamatanDropdown"
|
||||||
|
data-placeholder="Kecamatan .....">
|
||||||
|
<option></option>
|
||||||
|
<option value="1">Option 1</option>
|
||||||
|
<option value="2">Option 2</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<canvas id="canvas" style="width=100%"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <canvas id="myChart" style="width:80%;max-width:400px; margin-left: 20px;"></canvas> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="{{ url_for('static', filename='script.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery-3.7.1.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/bootstrap.min.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/select2.min.js')}}"></script>
|
||||||
|
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// const map = L.map('map').setView([4.2, 96.9], 7);
|
||||||
|
const indonesiaBounds = L.latLngBounds(
|
||||||
|
L.latLng(-11, 94), // Southwest corner (approx Sabang - Rote)
|
||||||
|
L.latLng(6.5, 141) // Northeast corner (approx Papua)
|
||||||
|
);
|
||||||
|
const map = L.map('map', {
|
||||||
|
center: [-2, 118], // Pusat Indonesia
|
||||||
|
// zoom: 5,
|
||||||
|
maxBounds: indonesiaBounds,
|
||||||
|
maxBoundsViscosity: 1.0,
|
||||||
|
zoomSnap: 0.5,
|
||||||
|
zoomDelta: 0.5
|
||||||
|
});
|
||||||
|
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© OpenStreetMap',
|
||||||
|
maxZoom: 12
|
||||||
|
}).addTo(map);
|
||||||
|
map.fitBounds(indonesiaBounds);
|
||||||
|
const optimalZoom = map.getZoom();
|
||||||
|
map.setMinZoom(optimalZoom);
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
let currentLayer = null;
|
||||||
|
function loadLayer(url, onClickCallback, level = 'provinsi') {
|
||||||
|
currentLevel = level;
|
||||||
|
fetch(url)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
// 1. Fungsi validasi dan pembersih
|
||||||
|
function isValidCoord(coord) {
|
||||||
|
return Array.isArray(coord) &&
|
||||||
|
coord.length === 2 &&
|
||||||
|
typeof coord[0] === "number" &&
|
||||||
|
typeof coord[1] === "number" &&
|
||||||
|
!isNaN(coord[0]) &&
|
||||||
|
!isNaN(coord[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanCoordinates(multiPolygon) {
|
||||||
|
return multiPolygon.map(polygon =>
|
||||||
|
polygon.map(ring =>
|
||||||
|
ring.filter(coord => isValidCoord(coord))
|
||||||
|
).filter(ring => ring.length >= 4) // valid ring minimal 4 titik
|
||||||
|
).filter(polygon => polygon.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Bersihkan data sebelum digunakan
|
||||||
|
data.features.forEach(feature => {
|
||||||
|
if (feature.geometry.type === "MultiPolygon") {
|
||||||
|
feature.geometry.coordinates = cleanCoordinates(feature.geometry.coordinates);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (currentLayer) {
|
||||||
|
map.removeLayer(currentLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLayer = L.geoJSON(data, {
|
||||||
|
style: { color: "blue", weight: 2 },
|
||||||
|
onEachFeature: function (feature, layer) {
|
||||||
|
console.log(feature,layer)
|
||||||
|
let clickTimer = null;
|
||||||
|
layer.on('click', function (e) {
|
||||||
|
let kode = feature.properties.id;
|
||||||
|
console.log(kode)
|
||||||
|
// onClickCallback(kode);
|
||||||
|
if (clickTimer) {
|
||||||
|
// Double click detected
|
||||||
|
clearTimeout(clickTimer);
|
||||||
|
clickTimer = null;
|
||||||
|
|
||||||
|
// Aksi double click → Pindah layer
|
||||||
|
let kode = feature.properties.id;
|
||||||
|
onClickCallback(kode);
|
||||||
|
if (url.includes("/provinsi")) {
|
||||||
|
localStorage.setItem('kode_provinsi', feature.properties.kode)
|
||||||
|
} else if (currentLevel === 'kabupatenkota') {
|
||||||
|
localStorage.setItem('kode_kabupatenkota',feature.properties.kode)
|
||||||
|
}else if(currentLevel === 'kecamatan'){
|
||||||
|
localStorage.setItem('kode_kecamatan',feature.properties.kode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Single click → Tampilkan popup
|
||||||
|
clickTimer = setTimeout(async () => {
|
||||||
|
clickTimer = null;
|
||||||
|
if (url.includes("/provinsi")) {
|
||||||
|
localStorage.setItem('kode_provinsi', feature.properties.kode)
|
||||||
|
const status = await fetchStatusDesaByProvinsi(feature.properties.kode);
|
||||||
|
|
||||||
|
let klasifikasiHTML = "<li>Tidak ada data</li>";
|
||||||
|
if (Array.isArray(status?.[0])) {
|
||||||
|
indexDesaHTML = status[0]
|
||||||
|
.map(d => `${d[1]}: ${d[4]} / `)
|
||||||
|
.join("");
|
||||||
|
bumdesHTML = status[1]
|
||||||
|
.map(dt => `${dt[0]}:${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
danadesaHTML = `Dana :${status[2].jumlah_per_m}, Persentase : ${status[2].persentage}%`;
|
||||||
|
serapanHTML = status[3]
|
||||||
|
.map(([jabatan, nilai]) => {
|
||||||
|
const alias = jabatan === 'Pendamping Lokal Desa' ? 'PLD' :
|
||||||
|
jabatan === 'Pendamping Desa' ? 'PD' :
|
||||||
|
jabatan;
|
||||||
|
return `${alias}: ${nilai}`;
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
koperasiHTML = status[4]
|
||||||
|
.map(dt => `${dt[0]}: ${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
const popupContent = `
|
||||||
|
<strong>${feature.properties.nama}</strong><br/>
|
||||||
|
<strong>Status Desa:</strong>
|
||||||
|
<li>IDM - ${indexDesaHTML}</li>
|
||||||
|
<li>BUM - ${bumdesHTML}</li>
|
||||||
|
<li>DD - ${danadesaHTML}</li>
|
||||||
|
<li>SERAPAN - ${serapanHTML} </li>
|
||||||
|
<li>KOPERASI - ${koperasiHTML} </li>
|
||||||
|
`;
|
||||||
|
|
||||||
|
layer.bindPopup(popupContent).openPopup(e.latlng);
|
||||||
|
|
||||||
|
} else if (currentLevel === 'kabupatenkota') {
|
||||||
|
const province_code = localStorage.getItem('kode_provinsi');
|
||||||
|
localStorage.setItem('kode_kabupatenkota',feature.properties.kode)
|
||||||
|
const status = await fetchStatusDesaByKabupatenkota(province_code, feature.properties.kode);
|
||||||
|
let klasifikasiHTML = "<li>Tidak ada data</li>";
|
||||||
|
|
||||||
|
if (Array.isArray(status?.[0])) {
|
||||||
|
indexDesaHTML = status[0]
|
||||||
|
.map(d => `${d[1]}: ${d[5]} / `)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
bumdesHTML = status[1]
|
||||||
|
.map(dt => `${dt[0]}:${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
danadesaHTML = `Dana :${status[2].jumlah_per_m}, Persentase : ${status[2].persentage}%`;
|
||||||
|
serapanHTML = status[3]
|
||||||
|
.map(([jabatan, nilai]) => {
|
||||||
|
const alias = jabatan === 'Pendamping Lokal Desa' ? 'PLD' :
|
||||||
|
jabatan === 'Pendamping Desa' ? 'PD' :
|
||||||
|
jabatan;
|
||||||
|
return `${alias}: ${nilai} /`;
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
koperasiHTML = status[4]
|
||||||
|
.map(dt => `${dt[0]}: ${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
const popupContent = `
|
||||||
|
<strong>${feature.properties.nama}</strong><br/>
|
||||||
|
<strong>Status Desa (Kabupaten):</strong>
|
||||||
|
<li>IDM - ${indexDesaHTML}</li>
|
||||||
|
<li>BUM - ${bumdesHTML}</li>
|
||||||
|
<li>DD - ${danadesaHTML}</li>
|
||||||
|
<li>SERAPAN - ${serapanHTML} </li>
|
||||||
|
<li>KOPERASI - ${koperasiHTML} </li>
|
||||||
|
`;
|
||||||
|
|
||||||
|
layer.bindPopup(popupContent).openPopup(e.latlng);
|
||||||
|
|
||||||
|
} else if (currentLevel === 'kecamatan'){
|
||||||
|
const province_code = localStorage.getItem('kode_provinsi')
|
||||||
|
const region_code = localStorage.getItem('kode_kabupatenkota')
|
||||||
|
localStorage.setItem('kode_kecamatan',feature.properties.kode)
|
||||||
|
const status = await fetchStatusDesaByKecamatan(province_code, region_code, feature.properties.kode)
|
||||||
|
let klasifikasiHTML = "<li>Tidak ada data</li>";
|
||||||
|
|
||||||
|
if (Array.isArray(status?.[0])) {
|
||||||
|
indexDesaHTML = status[0]
|
||||||
|
.map(d => `${d[1]}: ${d[6]} / `)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
bumdesHTML = status[1]
|
||||||
|
.map(dt => `${dt[0]}:${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
danadesaHTML = `Dana :${status[2].jumlah_per_m}, Persentase : ${status[2].persentage}%`;
|
||||||
|
serapanHTML = status[3]
|
||||||
|
.map(([jabatan, nilai]) => {
|
||||||
|
const alias = jabatan === 'Pendamping Lokal Desa' ? 'PLD' :
|
||||||
|
jabatan === 'Pendamping Desa' ? 'PD' :
|
||||||
|
jabatan;
|
||||||
|
return `${alias}: ${nilai} /`;
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
koperasiHTML = status[4]
|
||||||
|
.map(dt => `${dt[0]}: ${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const popupContent =
|
||||||
|
`
|
||||||
|
<strong> ${feature.properties.nama}</strong>
|
||||||
|
<strong>Status Desa (Kecamatan):</strong>
|
||||||
|
<strong>Status Desa:</strong>
|
||||||
|
<li>IDM - ${indexDesaHTML}</li>
|
||||||
|
<li>BUM - ${bumdesHTML}</li>
|
||||||
|
<li>DD - ${danadesaHTML}</li>
|
||||||
|
<li>SERAPAN - ${serapanHTML} </li>
|
||||||
|
<li>KOPERASI - ${koperasiHTML} </li>
|
||||||
|
`
|
||||||
|
layer.bindPopup(popupContent).openPopup(e.latlng);
|
||||||
|
}else {
|
||||||
|
// Desa
|
||||||
|
const province_code = localStorage.getItem('kode_provinsi')
|
||||||
|
const region_code = localStorage.getItem('kode_kabupatenkota')
|
||||||
|
const district_code = localStorage.getItem('kode_kecamatan')
|
||||||
|
|
||||||
|
const status = await fetchStatusDesaByDesa(province_code, region_code , district_code, feature.properties.kode);
|
||||||
|
let klasifikasiHTML = "<li>Tidak ada data</li>";
|
||||||
|
|
||||||
|
if (Array.isArray(status?.[0])) {
|
||||||
|
indexDesaHTML = status[0]
|
||||||
|
.map(d => `${d[1]}: ${d[5]} / `)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
bumdesHTML = status[1]
|
||||||
|
.map(dt => `${dt[0]}:${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
danadesaHTML = `Dana :${status[2].jumlah_per_m}, Persentase : ${status[2].persentage}%`;
|
||||||
|
serapanHTML = status[3]
|
||||||
|
.map(([jabatan, nilai]) => {
|
||||||
|
const alias = jabatan === 'Pendamping Lokal Desa' ? 'PLD' :
|
||||||
|
jabatan === 'Pendamping Desa' ? 'PD' :
|
||||||
|
jabatan;
|
||||||
|
return `${alias}: ${nilai} /`;
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
koperasiHTML = status[4]
|
||||||
|
.map(dt => `${dt[0]}: ${dt[1]} / `)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
const popupContent = `
|
||||||
|
<strong>${feature.properties.nama}</strong><br/>
|
||||||
|
<strong>Status Desa (Desa):</strong>
|
||||||
|
<li>IDM - ${indexDesaHTML}</li>
|
||||||
|
<li>BUM - ${bumdesHTML}</li>
|
||||||
|
<li>DD - ${danadesaHTML}</li>
|
||||||
|
<li>SERAPAN - ${serapanHTML} </li>
|
||||||
|
<li>KOPERASI - ${koperasiHTML} </li>
|
||||||
|
`;
|
||||||
|
|
||||||
|
layer.bindPopup(popupContent).openPopup(e.latlng);
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
layer.bindPopup(feature.properties.nama);
|
||||||
|
}
|
||||||
|
console.log(currentLevel)
|
||||||
|
});
|
||||||
|
layer.bindPopup(feature.properties.nama);
|
||||||
|
}
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
map.fitBounds(currentLayer.getBounds());
|
||||||
|
setTimeout(() => {
|
||||||
|
map.invalidateSize();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStatusDesaByProvinsi(kodeProvinsi) {
|
||||||
|
const url = `http://localhost:5000/api/status-provinsi/${kodeProvinsi}`;
|
||||||
|
const urldd = `http://localhost:5000/api/provinsi/serapan/${kodeProvinsi}`;
|
||||||
|
const urlpd = `http://localhost:5000//api/provinsi/pendamping/${kodeProvinsi}`
|
||||||
|
const urlkop = `http://localhost:5000//api/provinsi/koperasi/${kodeProvinsi}`
|
||||||
|
const urlbd = `http://localhost:5000/api/provinsi/bumdes/${kodeProvinsi}`;
|
||||||
|
try {
|
||||||
|
const res = await fetch(url);
|
||||||
|
const bumdes = await fetch(urlbd)
|
||||||
|
const dd = await fetch(urldd)
|
||||||
|
const pd = await fetch(urlpd)
|
||||||
|
const kop = await fetch(urlkop)
|
||||||
|
|
||||||
|
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
const IPD = await res.json()
|
||||||
|
const bd = await bumdes.json()
|
||||||
|
const danadesa = await dd.json()
|
||||||
|
const dtpd = await pd.json()
|
||||||
|
const dtkop = await kop.json()
|
||||||
|
|
||||||
|
return [IPD,bd, danadesa, dtpd, dtkop];
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal ambil status desa:", err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStatusDesaByKabupatenkota(kode_prov, kode_kabkota) {
|
||||||
|
const url = `http://localhost:5000/api/status-kabupatenkota/${kode_prov}/${kode_kabkota}`
|
||||||
|
const urldd = `http://localhost:5000/api/kabkota/serapan/${kode_kabkota}`;
|
||||||
|
const urlpd = `http://localhost:5000//api/kabkota/pendamping/${kode_kabkota}`
|
||||||
|
const urlkop = `http://localhost:5000//api/kabkota/koperasi/${kode_kabkota}`
|
||||||
|
const urlbd = `http://localhost:5000/api/kabkota/bumdes/${kode_kabkota}`;
|
||||||
|
try{
|
||||||
|
const res = await fetch(url)
|
||||||
|
const bumdes = await fetch(urlbd)
|
||||||
|
const dd = await fetch(urldd)
|
||||||
|
const pd = await fetch(urlpd)
|
||||||
|
const kop = await fetch(urlkop)
|
||||||
|
|
||||||
|
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
const IPD = await res.json()
|
||||||
|
const bd = await bumdes.json()
|
||||||
|
const danadesa = await dd.json()
|
||||||
|
const dtpd = await pd.json()
|
||||||
|
const dtkop = await kop.json()
|
||||||
|
|
||||||
|
return [IPD,bd, danadesa, dtpd, dtkop];
|
||||||
|
}catch(err){
|
||||||
|
console.log(err)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStatusDesaByKecamatan(province_code, region_code, district_code){
|
||||||
|
const url = `http://localhost:5000/api/status-kecamatan/${province_code}/${region_code}/${district_code}`
|
||||||
|
const urldd = `http://localhost:5000/api/kecamatan/serapan/${district_code}`;
|
||||||
|
const urlpd = `http://localhost:5000//api/kecamatan/pendamping/${district_code}`
|
||||||
|
const urlkop = `http://localhost:5000//api/kecamatan/koperasi/${district_code}`
|
||||||
|
const urlbd = `http://localhost:5000/api/kecamatan/bumdes/${district_code}`;
|
||||||
|
try {
|
||||||
|
const res = await fetch(url)
|
||||||
|
const bumdes = await fetch(urlbd)
|
||||||
|
const dd = await fetch(urldd)
|
||||||
|
const pd = await fetch(urlpd)
|
||||||
|
const kop = await fetch(urlkop)
|
||||||
|
|
||||||
|
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
const IPD = await res.json()
|
||||||
|
const bd = await bumdes.json()
|
||||||
|
const danadesa = await dd.json()
|
||||||
|
const dtpd = await pd.json()
|
||||||
|
const dtkop = await kop.json()
|
||||||
|
|
||||||
|
return [IPD,bd, danadesa, dtpd, dtkop];;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStatusDesaByDesa(province_code, region_code, district_code, village_code){
|
||||||
|
const url = `http://localhost:5000//api/desa/status/${province_code}/${region_code}/${district_code}/${village_code}`
|
||||||
|
const urldd = `http://localhost:5000/api/desa/serapan/${village_code}`;
|
||||||
|
const urlpd = `http://localhost:5000//api/desa/pendamping/${village_code}`
|
||||||
|
const urlkop = `http://localhost:5000//api/desa/koperasi/${village_code}`
|
||||||
|
const urlbd = `http://localhost:5000/api/desa/bumdes/${village_code}`;
|
||||||
|
try {
|
||||||
|
const res = await fetch(url)
|
||||||
|
const bumdes = await fetch(urlbd)
|
||||||
|
const dd = await fetch(urldd)
|
||||||
|
const pd = await fetch(urlpd)
|
||||||
|
const kop = await fetch(urlkop)
|
||||||
|
|
||||||
|
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
const IPD = await res.json()
|
||||||
|
const bd = await bumdes.json()
|
||||||
|
const danadesa = await dd.json()
|
||||||
|
const dtpd = await pd.json()
|
||||||
|
const dtkop = await kop.json()
|
||||||
|
|
||||||
|
return [IPD,bd, danadesa, dtpd, dtkop];;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load provinsi Aceh awal
|
||||||
|
loadLayer('/geojson/provinsi', function (kode_provinsi) {
|
||||||
|
loadLayer(`/geojson/kabupaten/${kode_provinsi}`, function (kode_kabupaten) {
|
||||||
|
loadLayer(`/geojson/kecamatan/${kode_kabupaten}`, function (kode_kecamatan) {
|
||||||
|
loadLayer(`/geojson/desa/${kode_kecamatan}`, function () {
|
||||||
|
// Desa tidak turun level lagi
|
||||||
|
}, 'desa');
|
||||||
|
}, 'kecamatan');
|
||||||
|
}, 'kabupatenkota');
|
||||||
|
}, 'provinsi');
|
||||||
|
|
||||||
|
function goToLevel(level) {
|
||||||
|
const prov = localStorage.getItem('kode_provinsi');
|
||||||
|
const kab = localStorage.getItem('kode_kabupatenkota');
|
||||||
|
const kec = localStorage.getItem('kode_kecamatan');
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case 'provinsi':
|
||||||
|
loadLayer(`/geojson/provinsi`, () => {}, 'provinsi');
|
||||||
|
break;
|
||||||
|
case 'kabupatenkota':
|
||||||
|
loadLayer(`/geojson/kabupaten/${prov}`, () => {}, 'kabupatenkota');
|
||||||
|
break;
|
||||||
|
case 'kecamatan':
|
||||||
|
loadLayer(`/geojson/kecamatan/${kab}`, () => {}, 'kecamatan');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#provinsiDropdown').on('change', function (e) {
|
||||||
|
const kodeProvinsi = $(this).val(); // lebih aman daripada e.target.value
|
||||||
|
console.log("Provinsi dipilih:", kodeProvinsi);
|
||||||
|
|
||||||
|
if (!kodeProvinsi) {
|
||||||
|
console.warn("Tidak ada kode provinsi yang dipilih!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem('kode_provinsi', kodeProvinsi);
|
||||||
|
|
||||||
|
console.log(`Memuat kabupaten dari /geojson/kabupaten/${kodeProvinsi}`);
|
||||||
|
loadLayer(`/geojson/kabupaten/${kodeProvinsi}`, () => {
|
||||||
|
console.log("Layer kabupaten dimuat.");
|
||||||
|
}, 'kabupatenkota');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#kabkotaDropdown').on('change', function (e) {
|
||||||
|
const kodeKabupaten = e.target.value;
|
||||||
|
|
||||||
|
localStorage.setItem('kode_kabupatenkota', kodeKabupaten);
|
||||||
|
loadLayer(`/geojson/kecamatan/${kodeKabupaten}`, () => {}, 'kecamatan');
|
||||||
|
}).select2();
|
||||||
|
|
||||||
|
document.getElementById('kecamatanDropdown').addEventListener('change', function (e) {
|
||||||
|
const kodeKecamatan = e.target.value;
|
||||||
|
localStorage.setItem('kode_kecamatan', kodeKecamatan);
|
||||||
|
loadLayer(`/geojson/desa/${kodeKecamatan}`, () => {}, 'desa');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
console.log("ready for fetching data")
|
||||||
|
const provinsiURL = "{{ url_for('main.get_master_provinsi') }}";
|
||||||
|
$('#provinsiDropdown').select2({
|
||||||
|
placeholder: 'Pilih Desa',
|
||||||
|
allowClear: true,
|
||||||
|
ajax: {
|
||||||
|
url: provinsiURL,
|
||||||
|
dataType: 'json',
|
||||||
|
delay: 250,
|
||||||
|
data: function (params) {
|
||||||
|
return {
|
||||||
|
q: params.term
|
||||||
|
};
|
||||||
|
},
|
||||||
|
processResults: function (data) {
|
||||||
|
console.log(data)
|
||||||
|
return {
|
||||||
|
results: data.map(provinsi => ({
|
||||||
|
id: provinsi[0],
|
||||||
|
text: provinsi[1]
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
},
|
||||||
|
cache: true
|
||||||
|
},
|
||||||
|
minimumInputLength: 0
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", (event) => {
|
||||||
|
$( '.select2' ).select2( {
|
||||||
|
theme: 'bootstrap-4'
|
||||||
|
} );
|
||||||
|
let total_dd_container = document.getElementById('tot_dd')
|
||||||
|
fetchTotDana('http://localhost:5000/api/desa/total-dana-desa')
|
||||||
|
fethTotSerapan('http://localhost:5000/api/desa/total-serapan-dana')
|
||||||
|
function fetchTotDana(url){
|
||||||
|
fetch(url)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
total_dd_container.textContent = parseDanBulatkanKeMiliar(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function fethTotSerapan(url){
|
||||||
|
fetch(url)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log(data)
|
||||||
|
document.getElementById('tot_sr').textContent = parseDanBulatkanKeMiliar(data['serapan_per_m'])
|
||||||
|
document.getElementById('pr_sr').textContent = data['persentage'] + "%"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDanBulatkanKeMiliar(input) {
|
||||||
|
// 1. Bersihkan input: hapus "Rp", ".", ganti koma dengan titik
|
||||||
|
let cleaned = input
|
||||||
|
.replace(/Rp/g, "")
|
||||||
|
.replace(/\./g, "")
|
||||||
|
.replace(",", ".");
|
||||||
|
|
||||||
|
// 2. Konversi ke angka
|
||||||
|
let angka = parseFloat(cleaned);
|
||||||
|
|
||||||
|
// 3. Bulatkan ke satuan miliar
|
||||||
|
let hasilBulat = Math.round(angka / 1e9);
|
||||||
|
|
||||||
|
// 4. Tambahkan format "x Miliar"
|
||||||
|
return "Rp" + hasilBulat.toLocaleString("id-ID") + " M";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Chart Script -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script>
|
||||||
|
var getRandomDataArray = function () {
|
||||||
|
var dataArray = [];
|
||||||
|
for (var i = 0; i < 7; i++) dataArray.push(Math.round(Math.random() * 100));
|
||||||
|
return dataArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.onload = function(){
|
||||||
|
var chartOptions = { responsive : true };
|
||||||
|
var chartData = {
|
||||||
|
labels : ["January","February","March","April","May","June","July"],
|
||||||
|
datasets : [
|
||||||
|
{
|
||||||
|
fillColor : "#ffa500",
|
||||||
|
strokeColor : "rgba(220,220,220,0.8)",
|
||||||
|
highlightFill: "rgba(220,220,220,0.75)",
|
||||||
|
highlightStroke: "rgba(220,220,220,1)",
|
||||||
|
data : getRandomDataArray()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fillColor : "rgba(151,187,205,0.5)",
|
||||||
|
strokeColor : "rgba(151,187,205,0.8)",
|
||||||
|
highlightFill : "rgba(151,187,205,0.75)",
|
||||||
|
highlightStroke : "rgba(151,187,205,1)",
|
||||||
|
data : getRandomDataArray()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
var chart = document.getElementById("canvas").getContext("2d");
|
||||||
|
window.myBar = new Chart(chart, {
|
||||||
|
type: "bar", // <- gunakan type di sini, bukan .Bar()
|
||||||
|
data: chartData,
|
||||||
|
options: chartOptions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user