Compare commits
No commits in common. "step4" and "api" have entirely different histories.
110
py6/app.py
110
py6/app.py
|
@ -1,110 +0,0 @@
|
|||
import sys
|
||||
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QPushButton, QLabel, QMessageBox, QFileDialog)
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QPixmap
|
||||
import requests
|
||||
|
||||
class PassportForm(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setWindowTitle("PAssportForms")
|
||||
|
||||
self.main_layout = QHBoxLayout()
|
||||
self.form_layout = QVBoxLayout()
|
||||
self.data_layout = QFormLayout()
|
||||
|
||||
self.number_input = QLineEdit()
|
||||
self.name_input = QLineEdit()
|
||||
self.surname_input = QLineEdit()
|
||||
self.gender_input = QLineEdit()
|
||||
self.fingerprint_url_input = QLineEdit()
|
||||
self.photo_url_input = QLineEdit()
|
||||
|
||||
self.data_layout.addRow("Passport Number", self.number_input)
|
||||
self.data_layout.addRow("Name", self.name_input)
|
||||
self.data_layout.addRow("Surname", self.surname_input)
|
||||
self.data_layout.addRow("Gender", self.gender_input)
|
||||
self.data_layout.addRow("Fingerprint URL", self.fingerprint_url_input)
|
||||
self.data_layout.addRow("Photo URL", self.photo_url_input)
|
||||
|
||||
self.load_button = QPushButton("Load Data")
|
||||
self.load_button.clicked.connect(self.load_data)
|
||||
|
||||
self.submit_button = QPushButton("Submit")
|
||||
self.submit_button.clicked.connect(self.submit_form)
|
||||
|
||||
self.form_layout.addLayout(self.data_layout)
|
||||
self.form_layout.addWidget(self.load_button)
|
||||
self.form_layout.addWidget(self.submit_button)
|
||||
|
||||
self.image_layout = QVBoxLayout()
|
||||
|
||||
self.photo_label = QLabel("Photo")
|
||||
self.photo_label.setFixedSize(200, 200)
|
||||
self.photo_label.setStyleSheet("border: 1px solid black;")
|
||||
self.photo_label.setAlignment(Qt.AlignCenter)
|
||||
|
||||
self.fingerprint_label = QLabel("Fingerprint")
|
||||
self.fingerprint_label.setFixedSize(200, 200)
|
||||
self.fingerprint_label.setStyleSheet("border: 1px solid black;")
|
||||
self.fingerprint_label.setAlignment(Qt.AlignCenter)
|
||||
|
||||
self.image_layout.addWidget(self.photo_label)
|
||||
self.image_layout.addWidget(self.fingerprint_label)
|
||||
|
||||
self.main_layout.addLayout(self.form_layout)
|
||||
self.main_layout.addLayout(self.image_layout)
|
||||
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
def load_data(self):
|
||||
passport_number = self.number_input.text()
|
||||
response = requests.get(f"http://localhost:9999/passport/{passport_number}")
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
self.name_input.setText(data['name'])
|
||||
self.surname_input.setText(data['surname'])
|
||||
self.gender_input.setText(data['gender'])
|
||||
self.fingerprint_url_input.setText(data['fingerprint_url'])
|
||||
self.photo_url_input.setText(data['photo_url'])
|
||||
|
||||
self.load_image(self.photo_label, f"http://localhost:9999/static/imgs/data/{passport_number}-zdjecie.jpg")
|
||||
self.load_image(self.fingerprint_label, f"http://localhost:9999/static/imgs/data/{passport_number}-odcisk.jpg")
|
||||
else:
|
||||
QMessageBox.critical(self, "Error", "Failed to load passport data")
|
||||
|
||||
def load_image(self, label, url):
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
pixmap = QPixmap()
|
||||
pixmap.loadFromData(response.content)
|
||||
label.setPixmap(pixmap.scaled(label.size(), Qt.KeepAspectRatio))
|
||||
else:
|
||||
label.setText("Image not found")
|
||||
|
||||
def submit_form(self):
|
||||
passport_data = {
|
||||
"number": self.number_input.text(),
|
||||
"name": self.name_input.text(),
|
||||
"surname": self.surname_input.text(),
|
||||
"gender": self.gender_input.text(),
|
||||
"fingerprint_url": self.fingerprint_url_input.text(),
|
||||
"photo_url": self.photo_url_input.text()
|
||||
}
|
||||
|
||||
response = requests.post("http://localhost:9999/passport/", json=passport_data)
|
||||
|
||||
if response.status_code == 200:
|
||||
QMessageBox.information(self, "Success", "Passport data submitted successfully")
|
||||
else:
|
||||
QMessageBox.critical(self, "Error", "Failed to submit passport data")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
window = PassportForm()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
|
|
@ -161,165 +161,3 @@ xmap <c-c><c-c> <Plug>SlimeRegionSend
|
|||
nmap <c-c><c-c> :<c-u>call SendCell('^#%%')<cr>
|
||||
nmap <c-c>v <Plug>SlimeConfig
|
||||
|
||||
" https://raw.githubusercontent.com/neoclide/coc.nvim/master/doc/coc-example-config.vim
|
||||
|
||||
" May need for Vim (not Neovim) since coc.nvim calculates byte offset by count
|
||||
" utf-8 byte sequence
|
||||
set encoding=utf-8
|
||||
" Some servers have issues with backup files, see #649
|
||||
set nobackup
|
||||
set nowritebackup
|
||||
|
||||
" Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
|
||||
" delays and poor user experience
|
||||
set updatetime=300
|
||||
|
||||
" Always show the signcolumn, otherwise it would shift the text each time
|
||||
" diagnostics appear/become resolved
|
||||
set signcolumn=yes
|
||||
|
||||
" Use tab for trigger completion with characters ahead and navigate
|
||||
" NOTE: There's always complete item selected by default, you may want to enable
|
||||
" no select by `"suggest.noselect": true` in your configuration file
|
||||
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
|
||||
" other plugin before putting this into your config
|
||||
inoremap <silent><expr> <TAB>
|
||||
\ coc#pum#visible() ? coc#pum#next(1) :
|
||||
\ CheckBackspace() ? "\<Tab>" :
|
||||
\ coc#refresh()
|
||||
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"
|
||||
|
||||
" Make <CR> to accept selected completion item or notify coc.nvim to format
|
||||
" <C-g>u breaks current undo, please make your own choice
|
||||
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
|
||||
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
|
||||
|
||||
function! CheckBackspace() abort
|
||||
let col = col('.') - 1
|
||||
return !col || getline('.')[col - 1] =~# '\s'
|
||||
endfunction
|
||||
|
||||
" Use <c-space> to trigger completion
|
||||
if has('nvim')
|
||||
inoremap <silent><expr> <c-space> coc#refresh()
|
||||
else
|
||||
inoremap <silent><expr> <c-@> coc#refresh()
|
||||
endif
|
||||
|
||||
" Use `[g` and `]g` to navigate diagnostics
|
||||
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
|
||||
nmap <silent> [g <Plug>(coc-diagnostic-prev)
|
||||
nmap <silent> ]g <Plug>(coc-diagnostic-next)
|
||||
|
||||
" GoTo code navigation
|
||||
nmap <silent> gd <Plug>(coc-definition)
|
||||
nmap <silent> gy <Plug>(coc-type-definition)
|
||||
nmap <silent> gi <Plug>(coc-implementation)
|
||||
nmap <silent> gr <Plug>(coc-references)
|
||||
|
||||
" Use K to show documentation in preview window
|
||||
nnoremap <silent> K :call ShowDocumentation()<CR>
|
||||
|
||||
function! ShowDocumentation()
|
||||
if CocAction('hasProvider', 'hover')
|
||||
call CocActionAsync('doHover')
|
||||
else
|
||||
call feedkeys('K', 'in')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Highlight the symbol and its references when holding the cursor
|
||||
autocmd CursorHold * silent call CocActionAsync('highlight')
|
||||
|
||||
" Symbol renaming
|
||||
nmap <leader>rn <Plug>(coc-rename)
|
||||
|
||||
" Formatting selected code
|
||||
xmap <leader>f <Plug>(coc-format-selected)
|
||||
nmap <leader>f <Plug>(coc-format-selected)
|
||||
|
||||
augroup mygroup
|
||||
autocmd!
|
||||
" Setup formatexpr specified filetype(s)
|
||||
autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
|
||||
" Update signature help on jump placeholder
|
||||
autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
|
||||
augroup end
|
||||
|
||||
" Applying code actions to the selected code block
|
||||
" Example: `<leader>aap` for current paragraph
|
||||
xmap <leader>a <Plug>(coc-codeaction-selected)
|
||||
nmap <leader>a <Plug>(coc-codeaction-selected)
|
||||
|
||||
" Remap keys for applying code actions at the cursor position
|
||||
nmap <leader>ac <Plug>(coc-codeaction-cursor)
|
||||
" Remap keys for apply code actions affect whole buffer
|
||||
nmap <leader>as <Plug>(coc-codeaction-source)
|
||||
" Apply the most preferred quickfix action to fix diagnostic on the current line
|
||||
nmap <leader>qf <Plug>(coc-fix-current)
|
||||
|
||||
" Remap keys for applying refactor code actions
|
||||
nmap <silent> <leader>re <Plug>(coc-codeaction-refactor)
|
||||
xmap <silent> <leader>r <Plug>(coc-codeaction-refactor-selected)
|
||||
nmap <silent> <leader>r <Plug>(coc-codeaction-refactor-selected)
|
||||
|
||||
" Run the Code Lens action on the current line
|
||||
nmap <leader>cl <Plug>(coc-codelens-action)
|
||||
|
||||
" Map function and class text objects
|
||||
" NOTE: Requires 'textDocument.documentSymbol' support from the language server
|
||||
xmap if <Plug>(coc-funcobj-i)
|
||||
omap if <Plug>(coc-funcobj-i)
|
||||
xmap af <Plug>(coc-funcobj-a)
|
||||
omap af <Plug>(coc-funcobj-a)
|
||||
xmap ic <Plug>(coc-classobj-i)
|
||||
omap ic <Plug>(coc-classobj-i)
|
||||
xmap ac <Plug>(coc-classobj-a)
|
||||
omap ac <Plug>(coc-classobj-a)
|
||||
|
||||
" Remap <C-f> and <C-b> to scroll float windows/popups
|
||||
if has('nvim-0.4.0') || has('patch-8.2.0750')
|
||||
nnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
|
||||
nnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
|
||||
inoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(1)\<cr>" : "\<Right>"
|
||||
inoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(0)\<cr>" : "\<Left>"
|
||||
vnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
|
||||
vnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
|
||||
endif
|
||||
|
||||
" Use CTRL-S for selections ranges
|
||||
" Requires 'textDocument/selectionRange' support of language server
|
||||
nmap <silent> <C-s> <Plug>(coc-range-select)
|
||||
xmap <silent> <C-s> <Plug>(coc-range-select)
|
||||
|
||||
" Add `:Format` command to format current buffer
|
||||
command! -nargs=0 Format :call CocActionAsync('format')
|
||||
|
||||
" Add `:Fold` command to fold current buffer
|
||||
command! -nargs=? Fold :call CocAction('fold', <f-args>)
|
||||
|
||||
" Add `:OR` command for organize imports of the current buffer
|
||||
command! -nargs=0 OR :call CocActionAsync('runCommand', 'editor.action.organizeImport')
|
||||
|
||||
" Add (Neo)Vim's native statusline support
|
||||
" NOTE: Please see `:h coc-status` for integrations with external plugins that
|
||||
" provide custom statusline: lightline.vim, vim-airline
|
||||
set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}
|
||||
|
||||
" Mappings for CoCList
|
||||
" Show all diagnostics
|
||||
nnoremap <silent><nowait> <space>a :<C-u>CocList diagnostics<cr>
|
||||
" Manage extensions
|
||||
nnoremap <silent><nowait> <space>e :<C-u>CocList extensions<cr>
|
||||
" Show commands
|
||||
nnoremap <silent><nowait> <space>c :<C-u>CocList commands<cr>
|
||||
" Find symbol of current document
|
||||
nnoremap <silent><nowait> <space>o :<C-u>CocList outline<cr>
|
||||
" Search workspace symbols
|
||||
nnoremap <silent><nowait> <space>s :<C-u>CocList -I symbols<cr>
|
||||
" Do default action for next item
|
||||
nnoremap <silent><nowait> <space>j :<C-u>CocNext<CR>
|
||||
" Do default action for previous item
|
||||
nnoremap <silent><nowait> <space>k :<C-u>CocPrev<CR>
|
||||
" Resume latest coc list
|
||||
nnoremap <silent><nowait> <space>p :<C-u>CocListResume<CR>
|
||||
|
|
|
@ -24,11 +24,3 @@ from sqlalchemy import text
|
|||
with engine.connect() as conn:
|
||||
result = conn.execute(text("select 'hello world'"))
|
||||
print(result.all())
|
||||
|
||||
#%%
|
||||
with engine.connect() as conn:
|
||||
result = conn.execute(text("show tables;"))
|
||||
#%%
|
||||
for row in result.fetchall():
|
||||
print(row)
|
||||
|
||||
|
|
|
@ -1,28 +1,21 @@
|
|||
# app/main.py
|
||||
|
||||
# ---
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Depends
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
from app.database import SessionLocal, engine
|
||||
from app import models, schemas
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
# ddfrom starlette.middleware.base import BaseHTTPMiddleware
|
||||
# from starlette.responses import Response
|
||||
|
||||
# class CustomMIMEMiddleware(BaseHTTPMiddleware):
|
||||
# async def dispatch(self, request, call_next):
|
||||
# response = await call_next(request)
|
||||
# if request.url.path.endswith('.vue'):
|
||||
# response.headers['Content-Type'] = 'application/javascript'
|
||||
# return response
|
||||
from app.database import SessionLocal
|
||||
from app.models import PassportData
|
||||
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from typing import List, Optional
|
||||
|
||||
app = FastAPI()
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
models.Base.metadata.create_all(bind=engine)
|
||||
|
||||
# Dependency to get DB session
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
|
@ -30,18 +23,24 @@ def get_db():
|
|||
finally:
|
||||
db.close()
|
||||
|
||||
@app.post("/passport/", response_model=schemas.PassportData)
|
||||
def create_passport_data(passport_data: schemas.PassportDataCreate, db: Session = Depends(get_db)):
|
||||
db_passport_data = models.PassportData(**passport_data.dict())
|
||||
db.add(db_passport_data)
|
||||
class PassportDataRequest(BaseModel):
|
||||
number: str
|
||||
name: str
|
||||
surname: str
|
||||
gender: str
|
||||
|
||||
@app.post("/passport_data/")
|
||||
def create_passport_data(request: PassportDataRequest, db: Session = Depends(get_db)):
|
||||
db_passport = PassportData(number=request.number, name=request.name, surname=request.surname, gender=request.gender)
|
||||
db.add(db_passport)
|
||||
db.commit()
|
||||
db.refresh(db_passport_data)
|
||||
return db_passport_data
|
||||
db.refresh(db_passport)
|
||||
return db_passport
|
||||
|
||||
@app.get("/passport/{passport_number}", response_model=schemas.PassportData)
|
||||
@app.get("/passport_data/{passport_number}")
|
||||
def read_passport_data(passport_number: str, db: Session = Depends(get_db)):
|
||||
db_passport_data = db.query(models.PassportData).filter(models.PassportData.number == passport_number).first()
|
||||
if db_passport_data is None:
|
||||
db_passport = db.query(PassportData).filter(PassportData.number == passport_number).first()
|
||||
if db_passport is None:
|
||||
raise HTTPException(status_code=404, detail="Passport data not found")
|
||||
return schemas.PassportData.from_orm(db_passport_data)
|
||||
return db_passport
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# app/models.py
|
||||
from sqlalchemy import Column, Integer, String
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.database import Base
|
||||
|
||||
class PassportData(Base):
|
||||
__tablename__ = 'passport_data'
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
number = Column(String(255), unique=True, nullable=False)
|
||||
name = Column(String(255), nullable=True)
|
||||
surname = Column(String(255), nullable=True)
|
||||
gender = Column(String(255), nullable=True)
|
||||
fingerprint_url = Column(String(255), nullable=True) # New field for fingerprint image URL
|
||||
photo_url = Column(String(255), nullable=True) # New field for photo image URL
|
||||
name = Column(String(255), nullable=False)
|
||||
surname = Column(String(255), nullable=False)
|
||||
gender = Column(String(255), nullable=False)
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
# app/schemas.py
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
class PassportDataBase(BaseModel):
|
||||
number: str
|
||||
name: Optional[str] = None
|
||||
surname: Optional[str] = None
|
||||
gender: Optional[str] = None
|
||||
fingerprint_url: Optional[str] = None
|
||||
photo_url: Optional[str] = None
|
||||
|
||||
class PassportDataCreate(PassportDataBase):
|
||||
pass
|
||||
|
||||
class PassportData(PassportDataBase):
|
||||
id: int
|
||||
|
||||
class Config:
|
||||
orm_mode = True # Poprawne przypisanie
|
||||
|
|
@ -1,76 +1,25 @@
|
|||
# entrypoint.py
|
||||
#%%
|
||||
from app.database import engine, SessionLocal
|
||||
from app.models import Base, PassportData
|
||||
from app.database import engine
|
||||
from app.models import Base
|
||||
import argparse
|
||||
|
||||
import uvicorn
|
||||
import os
|
||||
|
||||
#%%
|
||||
def load_data_from_directory(directory_path: str, db_session):
|
||||
files = os.listdir(directory_path)
|
||||
passport_data = {}
|
||||
|
||||
for file in files:
|
||||
file_parts = file.split('-')
|
||||
if len(file_parts) != 2:
|
||||
continue
|
||||
|
||||
passport_number = file_parts[0]
|
||||
file_type = file_parts[1].split('.')[0]
|
||||
|
||||
if passport_number not in passport_data:
|
||||
passport_data[passport_number] = {
|
||||
"fingerprint_url": None,
|
||||
"photo_url": None
|
||||
}
|
||||
|
||||
file_path = os.path.join(directory_path, file)
|
||||
if file_type == 'odcisk':
|
||||
passport_data[passport_number]["fingerprint_url"] = file_path
|
||||
elif file_type == 'zdjecie':
|
||||
passport_data[passport_number]["photo_url"] = file_path
|
||||
|
||||
for number, data in passport_data.items():
|
||||
passport_entry = PassportData(
|
||||
number=number,
|
||||
name=None,
|
||||
surname=None,
|
||||
gender=None,
|
||||
fingerprint_url=data["fingerprint_url"],
|
||||
photo_url=data["photo_url"]
|
||||
)
|
||||
db_session.add(passport_entry)
|
||||
print (passport_entry)
|
||||
db_session.commit()
|
||||
|
||||
|
||||
|
||||
#%%
|
||||
def main(port, data_dir):
|
||||
def main(port):
|
||||
# Create the database
|
||||
print("Creating database tables...")
|
||||
Base.metadata.create_all(bind=engine)
|
||||
print("Database tables created.")
|
||||
|
||||
db_session = SessionLocal()
|
||||
try:
|
||||
print(f"Loading data from directory: {data_dir}")
|
||||
load_data_from_directory(data_dir, db_session)
|
||||
print("Data loaded into database.")
|
||||
finally:
|
||||
db_session.close()
|
||||
|
||||
# uvicorn.run("app.main:app", host="0.0.0.0", port=port, reload=True)
|
||||
|
||||
#%% main(9999,"data")
|
||||
|
||||
|
||||
#%%
|
||||
# Run the FastAPI app using uvicorn
|
||||
# uvicorn.run("app.main:app", host="0.0.0.0", port=port, reload=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Create argument parser
|
||||
parser = argparse.ArgumentParser(description="Run the FastAPI app")
|
||||
# Add port argument, default is 9999
|
||||
parser.add_argument("--port", type=int, default=9999, help="Port to run the FastAPI app on")
|
||||
parser.add_argument("--data-dir", type=str, default="data", help="Directory containing passport data files")
|
||||
# Parse arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
main(args.port, args.data_dir)
|
||||
main(args.port)
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
curl -X POST "http://localhost:9999/passport/" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"number": "444",
|
||||
"name": null,
|
||||
"surname": null,
|
||||
"gender": null,
|
||||
"fingerprint_url": "data/444-odcisk.jpg",
|
||||
"photo_url": "data/444-zdjecie.jpg"
|
||||
}'
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 41 KiB |
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
Binary file not shown.
Before Width: | Height: | Size: 46 KiB |
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
|
@ -1,16 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Passport Form App</title>
|
||||
<link rel="stylesheet" href="./style.css">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Library Management</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="app"></div>
|
||||
<script src="./js/axios.min.js"></script>
|
||||
<script type="module" src="./script.js"></script>
|
||||
|
||||
<header>Library Management</header>
|
||||
<div class="container">
|
||||
<aside class="sidebar">
|
||||
<h2>Add Author</h2>
|
||||
<form id="addAuthorForm">
|
||||
<input type="text" id="authorName" placeholder="Author Name" required>
|
||||
<button type="submit">Add Author</button>
|
||||
</form>
|
||||
<h2>Add Book</h2>
|
||||
<form id="addBookForm">
|
||||
<input type="text" id="bookTitle" placeholder="Book Title" required>
|
||||
<select id="bookAuthorId">
|
||||
<!-- Autorzy będą dodawani tutaj dynamicznie -->
|
||||
</select>
|
||||
<button type="submit">Add Book</button>
|
||||
</form>
|
||||
</aside>
|
||||
<main class="content">
|
||||
<h2>Authors</h2>
|
||||
<ul id="authorsList"></ul>
|
||||
<h2>Books</h2>
|
||||
<ul id="booksList"></ul>
|
||||
<button id="loadBooksWithAuthors">Load Books with Authors</button>
|
||||
<ul id="booksWithAuthorsList"></ul>
|
||||
</main>
|
||||
</div>
|
||||
<footer>2024 Library Management System</footer>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -1,16 +1,69 @@
|
|||
import { createApp } from './js/vue.esm-browser.js';
|
||||
import PassportForm from './components/Tabs.js';
|
||||
const BASE_URL = 'http://qstack.pl:1111'; // Zaktualizuj zgodnie z konfiguracją Twojego serwera
|
||||
|
||||
const App = {
|
||||
name: 'App',
|
||||
components: {
|
||||
PassportForm
|
||||
},
|
||||
template: `
|
||||
<div id="app">
|
||||
<PassportForm />
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadAuthors();
|
||||
loadBooks();
|
||||
});
|
||||
|
||||
document.getElementById('addAuthorForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const authorName = document.getElementById('authorName').value;
|
||||
fetch(`${BASE_URL}/authors/`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name: authorName }),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
loadAuthors(); // Ponowne ładowanie listy autorów po dodaniu nowego autora
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
});
|
||||
|
||||
document.getElementById('addBookForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const bookTitle = document.getElementById('bookTitle').value;
|
||||
const bookAuthorId = document.getElementById('bookAuthorId').value;
|
||||
fetch(`${BASE_URL}/books/`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ title: bookTitle, author_id: parseInt(bookAuthorId, 10) }),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
loadBooks(); // Ponowne ładowanie listy książek po dodaniu nowej książki
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
});
|
||||
|
||||
function loadAuthors() {
|
||||
fetch(`${BASE_URL}/authors/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const authorsSelect = document.getElementById('bookAuthorId');
|
||||
authorsSelect.innerHTML = '<option value="">Select an Author</option>'; // Dodaj domyślną opcję
|
||||
data.forEach(author => {
|
||||
const option = document.createElement('option');
|
||||
option.value = author.id;
|
||||
option.textContent = author.name;
|
||||
authorsSelect.appendChild(option);
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
}
|
||||
|
||||
function loadBooks() {
|
||||
fetch(`${BASE_URL}/books/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const booksList = document.getElementById('booksList');
|
||||
booksList.innerHTML = '';
|
||||
data.forEach(book => {
|
||||
const listItem = document.createElement('li');
|
||||
listItem.textContent = `${book.title} - Author ID: ${book.author_id}`;
|
||||
booksList.appendChild(listItem);
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
}
|
||||
|
||||
createApp(App).mount('#app');
|
||||
|
|
|
@ -1,33 +1,43 @@
|
|||
.passport-form {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-top: 20px;
|
||||
}
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin-right: 20px;
|
||||
}
|
||||
header, footer {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
.container {
|
||||
display: flex;
|
||||
min-height: calc(100vh - 100px); /* Adjust based on header/footer height */
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 30%;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
form > * {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-field label {
|
||||
margin-right: 10px;
|
||||
}
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.images-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.images-container img {
|
||||
max-width: 200px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue