fix aud search on center

This commit is contained in:
Your Name
2026-05-11 15:12:34 +03:00
parent 54534ee490
commit 9491909f24
61 changed files with 1049 additions and 2774 deletions

View File

@@ -0,0 +1,17 @@
{
"permissions": {
"allow": [
"Bash(backend\\\\venv\\\\Scripts\\\\python.exe -m uvicorn backend.main:app --reload)",
"Bash(python:*)",
"Bash(backend/venv/Scripts/python.exe:*)",
"Bash(backend/venv/Scripts/pip.exe list:*)",
"Bash(backend/venv/Scripts/pip.exe install:*)",
"Bash(backend/venv/Scripts/uvicorn.exe backend.main:app)",
"Bash(curl -s http://localhost:8000/ping)",
"Bash(curl -s http://127.0.0.1:8000/ping)",
"Bash(taskkill /F /IM python.exe)",
"Bash(netstat -ano)",
"Bash(taskkill:*)"
]
}
}

142
INSPECTION_GUIDE.md Normal file
View File

@@ -0,0 +1,142 @@
# Руководство по использованию системы проверки оборудования
## Обзор
Система проверки оборудования позволяет проводить инвентаризацию с использованием штрихкод-сканера или ручного ввода инвентарных номеров.
## Возможности
- ✅ Проверка оборудования по аудиториям или всего подряд
- ✅ Поддержка штрихкод-сканеров (работают как клавиатура)
- ✅ Автоматическое обновление времени при повторном сканировании
- ✅ Сохранение неизвестных номеров
- ✅ Отслеживание прогресса в реальном времени
- ✅ История всех проверок
- ✅ Доступ для всех авторизованных пользователей (включая viewer)
## Как использовать
### 1. Начать новую проверку
1. Войдите в систему
2. Перейдите в раздел "Проверка" в меню
3. (Опционально) Выберите аудиторию для проверки
- Если аудитория не выбрана, будет проверяться всё оборудование
4. Нажмите "Начать проверку"
### 2. Сканирование оборудования
После начала проверки:
1. Фокус автоматически установлен на поле ввода
2. Отсканируйте штрихкод или введите инвентарный номер вручную
3. Нажмите Enter (или сканер сделает это автоматически)
4. Система покажет результат:
-**Зелёное уведомление** - оборудование найдено
-**Красное уведомление** - номер не найден (сохранён в неизвестные)
5. Продолжайте сканирование следующих позиций
### 3. Отслеживание прогресса
Во время проверки отображается:
- **Проверено** - количество отсканированных позиций
- **Всего** - ожидаемое количество оборудования
- **Не найдено** - количество неизвестных штрихкодов
- **Прогресс** - процент завершения
### 4. Завершение проверки
1. После завершения сканирования нажмите "Завершить проверку"
2. Подтвердите действие
3. Проверка будет сохранена в историю
### 5. Просмотр истории
1. На главном экране проверок нажмите "Загрузить историю"
2. Выберите нужную проверку
3. Нажмите "Детали" для просмотра отчёта
## Работа со сканером штрихкодов
### Подключение
1. Подключите USB штрихкод-сканер к компьютеру
2. Сканер работает как клавиатура - не требует драйверов
3. Откройте страницу проверки в браузере
### Сканирование
1. Убедитесь, что фокус на поле ввода
2. Наведите сканер на штрихкод
3. Нажмите кнопку сканирования
4. Сканер введёт номер и нажмёт Enter автоматически
### Советы
- После каждого сканирования фокус автоматически возвращается на поле ввода
- Можно сканировать штрихкоды быстро один за другим
- Уведомления о результатах исчезают автоматически через 3 секунды
## Особенности
### Повторное сканирование
- При повторном сканировании одного и того же оборудования обновляется только время проверки
- В таблице остаётся одна запись на единицу оборудования
### Неизвестные номера
- Если номер не найден в базе данных, он сохраняется в список неизвестных
- Неизвестные номера отображаются отдельным списком
- Это помогает выявить ошибки маркировки или новое оборудование
### Доступ
- Все авторизованные пользователи могут проводить проверки
- Проверки можно просматривать, но нельзя удалять
- Каждая проверка привязана к пользователю, который её создал
## API Endpoints
Система предоставляет следующие API эндпоинты:
- `POST /inspections/sessions` - Начать новую проверку
- `POST /inspections/sessions/{id}/check` - Сканировать штрихкод
- `GET /inspections/sessions/{id}` - Получить статистику проверки
- `POST /inspections/sessions/{id}/complete` - Завершить проверку
- `GET /inspections/sessions` - Список всех проверок
- `GET /inspections/sessions/{id}/records` - Детальный отчёт
Полная документация доступна по адресу: http://localhost:8000/docs
## Устранение неполадок
### Сканер не работает
1. Проверьте USB подключение
2. Убедитесь, что фокус на поле ввода
3. Попробуйте отсканировать в текстовый редактор для проверки
4. Проверьте настройки сканера (должен добавлять Enter в конце)
### Оборудование не находится
1. Проверьте инвентарный номер в базе данных
2. Убедитесь, что штрихкод читается правильно
3. Проверьте список неизвестных штрихкодов
### Прогресс не обновляется
1. Нажмите кнопку "Обновить данные"
2. Проверьте подключение к серверу
3. Обновите страницу браузера
## База данных
Система использует три новые таблицы:
1. **inspection_sessions** - Сессии проверок
2. **inspection_records** - Записи о проверенном оборудовании
3. **unknown_barcodes** - Неизвестные штрихкоды
Таблицы создаются автоматически при запуске скрипта `create_inspection_tables.py`.

View File

344
app.py
View File

@@ -1,344 +0,0 @@
# -*- coding: utf-8 -*-
from flask import Flask, render_template, redirect, url_for, request, jsonify
from models import db, Oboruds, Auditory, Zametki
from flask_migrate import Migrate
from datetime import *
import csv
import random
from urllib.parse import unquote
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"
app.jinja_env.auto_reload = True
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.secret_key = '6523e58bc0eec42c31b9635d5e0dfc23b6d119b73e633bf3a5284c79bb4a1ede'
db.init_app(app)
migrate = Migrate(app, db)
@app.route("/login", methods=['GET', 'POST'])
def login():
return render_template('login.html')
@app.route("/", methods=['GET', 'POST'])
def index():
results = []
results1 = []
all_aud = db.session.query(Auditory).all()
auds = []
for item in all_aud:
auds.append(item.audnazvanie)
if request.method == 'POST':
p = request.form.get('srch').strip()
all_aud = db.session.query(Auditory).all()
s = db.session.query(Oboruds).filter(
Oboruds.invNumber.contains(p)).first()
if s:
for item in all_aud:
auds.append(item.audnazvanie)
if s.aud_id is None:
results.append([s.invNumber, s.nazvanie])
else:
results1.append(s.invNumber)
results1.append(s.nazvanie)
aud = db.session.get(Auditory, s.aud_id)
results1.append(aud.audnazvanie)
return render_template('index.html', aud=all_aud, results=results, res1=results1)
return render_template('index.html', aud=all_aud, results=results, res1=results1)
@app.route("/perenos", methods=['GET', 'POST'])
def perenos():
audid = request.args.get('audid')
invnomer = request.args.get('invnum')
ob = db.session.query(Oboruds).filter_by(invNumber=invnomer).first()
ob.aud_id = audid
db.session.commit()
return jsonify({'success': True}, 200, {'ContentType': 'application/json'})
@app.route("/addaud", methods=['GET', 'POST'])
def addAud():
return render_template('addaud.html', methods=['GET', 'POST'])
@app.route('/searchonaud', methods=['GET', 'POST'])
def searchonaud():
all_aud = db.session.query(Auditory).all()
res = []
if request.method == 'GET' and request.args.get('auditory'):
audid = request.args.get('auditory')
q = db.session.query(Auditory, Oboruds).filter(
Auditory.id == Oboruds.aud_id
).filter(Auditory.id == audid
).order_by(Oboruds.invNumber).all()
results = []
for auditory, oboruds in q:
results.append({
'num_ved': oboruds.numberved,
'auditory_id': auditory.id,
'auditory_name': auditory.audnazvanie,
'inv_number': oboruds.invNumber,
'oboruds_id': oboruds.nazvanie,
'raspolog': oboruds.raspologenie,
})
return jsonify(results)
else:
return render_template('searchonaud.html', aud=all_aud, res=res)
@app.route("/addaudtodb", methods=['GET', 'POST'])
def addaudtodb():
if request.method == 'POST':
aud = request.form.get('auditory')
db.session.add(Auditory(audnazvanie=aud))
db.session.commit()
return redirect(url_for('addAud'))
@app.route("/addoborudtodb", methods=['GET', 'POST'])
def addoborudtodb():
res = []
if request.method == 'POST':
audid = request.form.get('auditory')
invnomer = request.form.get('invnomer')
ob = db.session.query(Oboruds).filter_by(invNumber=invnomer).first()
ob.aud_id = audid
db.session.commit()
return redirect(url_for('index'))
@app.route('/all')
def alloborud():
return render_template('all.html')
@app.route('/getall')
def getall():
oborud = db.session.query(Oboruds).order_by(Oboruds.invNumber).all()
results = []
for oboruds in oborud:
if oboruds.aud_id is None:
results.append({
'invNumber': oboruds.invNumber,
'nazvanie': oboruds.nazvanie,
'raspologenie': oboruds.raspologenie,
'balancenumber': oboruds.balancenumber,
'kolichestvo': oboruds.kolichestvo,
'numberppasu': oboruds.numberppasu,
'numberved': oboruds.numberved,
'aud': ""})
else:
aud = db.session.query(Auditory).filter_by(id=oboruds.aud_id).first()
results.append({
'invNumber': oboruds.invNumber,
'nazvanie': oboruds.nazvanie,
'raspologenie': oboruds.raspologenie,
'balancenumber': oboruds.balancenumber,
'kolichestvo': oboruds.kolichestvo,
'numberppasu': oboruds.numberppasu,
'numberved': oboruds.numberved,
'aud': aud.audnazvanie})
return jsonify(results)
@app.route('/vneaud', methods=['GET', 'POST'])
def vneaud():
res = []
data = db.session.query(Oboruds).filter(Oboruds.aud_id == None).all()
ak = db.session.query(Oboruds).all()
for dt in data:
res.append([dt.invNumber, dt.nazvanie])
return render_template('vneaud.html', res=res, kolvo=len(data), all_kol=len(ak))
@app.route('/zametki', methods=['GET', 'POST'])
def zametki():
zam = db.session.query(Zametki).filter(Zametki.rmdt == None).all()
if request.method == 'POST':
textzam = request.form.get('textzam')
timeadd = datetime.now(timezone.utc)
if len(textzam) > 0:
db.session.add(Zametki(txtzam=textzam, created_date=timeadd))
db.session.commit()
return redirect(url_for('zametki'))
return render_template('zametki.html', zam=zam)
@app.route('/zamrm', methods=['GET', 'POST'])
def js2():
zmid = request.args.get('zmid')
ob = db.session.query(Zametki).filter_by(id=zmid).first()
ob.rmdt = datetime.now(timezone.utc)
db.session.commit()
return jsonify({'success': True}), 200, {'ContentType': 'application/json'}
@app.route('/zamsearch', methods=['GET', 'POST'])
def zamsearch():
p = request.form.get('srch')
searchedZam = db.session.query(Zametki).filter(
Zametki.txtzam.contains(p)).ll()
zam = []
for item in searchedZam:
zam.append([item.txtzam, item.created_date])
return render_template('zametki.html', zam=zam)
@app.route('/addraspved', methods=['GET', 'POST'])
def addraspved():
if request.method == 'POST':
query_string = request.data.decode()
un_query_string = unquote(unquote(query_string)).split(',')
ob = db.session.query(Oboruds).filter_by(invNumber=un_query_string[0]).first()
ob.numberved = un_query_string[1]
ob.kolichestvo = un_query_string[2]
ob.balancenumber = un_query_string[3]
ob.raspologenie = un_query_string[4]
db.session.commit()
db.session.close()
return jsonify({'success': True}, 200, {'ContentType': 'application/json'})
@app.route('/addoborudasu', methods=['GET', 'POST'])
def addoborud():
if request.method == 'POST':
query_string = request.data.decode()
un_query_string = unquote(unquote(query_string)).split(',')
db.session.add(
Oboruds(invNumber=un_query_string[0],
nazvanie=un_query_string[5],
raspologenie=un_query_string[4],
numberved=un_query_string[1],
kolichestvo=un_query_string[2],
balancenumber=un_query_string[3]
)
)
db.session.commit()
return jsonify({'success': True}, 200, {'ContentType': 'application/json'})
# ==================================================================================
def ranomraspr():
with app.app_context():
while len(db.session.query(Oboruds).filter(Oboruds.aud_id is None).all()) > 0:
audid = random.choice(db.session.query(Auditory).all())
oborud = random.choice(db.session.query(Oboruds).filter(Oboruds.aud_id is None).all())
oborud.aud_id = audid.id
db.session.commit()
def createdb():
with app.app_context():
db.create_all()
auds = ['519', '521', '521a', '522', '523',
'601л',
'602л',
'603л',
'604л',
'605л',
'606л',
'607л',
'608л',
'609л',
'610л',
'611л',
'612л',
'613л',
'616л',
'617л',
'618л',
'619л',
'620л',
'621л',
'622л',
'626л',
'627л',
'703л',
'710л',
'713л']
for aud in auds:
db.session.add(Auditory(audnazvanie=aud))
db.session.commit()
with open('inventMavrin.csv', encoding='cp1251') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=';')
for row in csv_reader:
db.session.add(
Oboruds(invNumber=row[0], nazvanie=row[1], typeBalanse='баланс'))
db.session.commit()
def write2excell():
wb = xlrd.open_workbook("VedIsh.xls")
sheet = wb.sheet_by_index(0)
newFile = copy(wb)
newSheet = newFile.get_sheet(0)
invNomerColum = 6
column_index = 1
for row_idx in range(sheet.nrows):
cell_value = sheet.cell(row_idx, column_index)
if cell_value:
tmp_inv_number = str(cell_value).split(':')[1]
try:
a = tmp_inv_number[1:-1]
inv_number = int(tmp_inv_number[1:-1])
with app.app_context():
auditory_obj = db.session.query(Auditory).join(Oboruds, Oboruds.aud_id == Auditory.id).filter(
Oboruds.invNumber == inv_number).first()
print(auditory_obj.audnazvanie)
# cur.execute("SELECT aud.audnazvanie FROM oboruds AS ob JOIN auditory AS aud ON ob.aud_id = aud.id WHERE ob.invNumber = ?", (inv_number,))
except:
pass
"""
else:
#newSheet.write(row_idx, invNomerColum, "Нет инв номера")
pass
newFile.save("Ved31.xls")
"""
if __name__ == '__main__':
#write2excell()
app.run(debug=True, host='0.0.0.0', port='3800')

View File

@@ -0,0 +1,11 @@
{
"permissions": {
"allow": [
"Bash(.venvScriptsactivate)",
"Bash(python:*)",
"Bash(venv/Scripts/python.exe:*)",
"Bash(timeout 5 tail:*)",
"Bash(curl:*)"
]
}
}

View File

@@ -12,6 +12,7 @@ from backend.routers.rashodniki import consumables
from backend.routers.zametki import zametki
from backend.routers.auth import auth
from backend.routers.owners import owners
from backend.routers.inspections import inspections
@@ -32,8 +33,7 @@ def ping():
return {"message": "pong"}
# Serve static assets and frontend
app.mount("/static", StaticFiles(directory="static"), name="static")
# Serve frontend
app.mount("/app", StaticFiles(directory="frontend", html=True), name="frontend")
@app.get("/")
@@ -46,11 +46,12 @@ def login_page():
# Подключение роутов
app.include_router(equipment_types)
app.include_router(auditories)
app.include_router(oboruds)
app.include_router(equipment_types)
app.include_router(auditories)
app.include_router(oboruds)
app.include_router(components)
app.include_router(consumables)
app.include_router(zametki)
app.include_router(auth)
app.include_router(owners)
app.include_router(inspections)

View File

@@ -1,6 +1,6 @@
# backend/models.py
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, UniqueConstraint
from sqlalchemy.orm import relationship, declarative_base
import datetime
@@ -98,3 +98,47 @@ class Zametki(Base):
txtzam = Column(String(10000))
created_date = Column(DateTime, default=datetime.datetime.utcnow)
rmdt = Column(DateTime)
class InspectionSession(Base):
__tablename__ = 'inspection_sessions'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
started_at = Column(DateTime, nullable=False)
completed_at = Column(DateTime, nullable=True)
aud_id = Column(Integer, ForeignKey("auditories.id"), nullable=True) # null = всё подряд
# Relationships
user = relationship("User")
auditory = relationship("Auditory")
records = relationship("InspectionRecord", back_populates="session")
unknown_barcodes = relationship("UnknownBarcode", back_populates="session")
class InspectionRecord(Base):
__tablename__ = 'inspection_records'
id = Column(Integer, primary_key=True)
session_id = Column(Integer, ForeignKey("inspection_sessions.id"), nullable=False)
oborud_id = Column(Integer, ForeignKey("oboruds.id"), nullable=False)
checked_at = Column(DateTime, nullable=False) # обновляется при повторном сканировании
# Relationships
session = relationship("InspectionSession", back_populates="records")
oborud = relationship("Oboruds")
# Уникальное ограничение: одна запись на оборудование в рамках сессии
__table_args__ = (UniqueConstraint('session_id', 'oborud_id', name='_session_oborud_uc'),)
class UnknownBarcode(Base):
__tablename__ = 'unknown_barcodes'
id = Column(Integer, primary_key=True)
session_id = Column(Integer, ForeignKey("inspection_sessions.id"), nullable=False)
barcode = Column(String(100), nullable=False)
scanned_at = Column(DateTime, nullable=False)
# Relationships
session = relationship("InspectionSession", back_populates="unknown_barcodes")

View File

@@ -16,7 +16,7 @@ class EquipmentTypeRead(EquipmentTypeBase):
id: int
class Config:
orm_mode = True
from_attributes = True
# === Component ===
@@ -31,7 +31,7 @@ class ComponentRead(ComponentBase):
id: int
class Config:
orm_mode = True
from_attributes = True
# === Consumable ===
@@ -46,7 +46,7 @@ class ConsumableRead(ConsumableBase):
id: int
class Config:
orm_mode = True
from_attributes = True
# === Owner ===
@@ -60,7 +60,7 @@ class OwnerRead(OwnerBase):
id: int
class Config:
orm_mode = True
from_attributes = True
# === Oborud ===
@@ -95,7 +95,7 @@ class OborudRead(OborudBase):
consumables: List[ConsumableRead] = []
class Config:
orm_mode = True
from_attributes = True
# === Auditory ===
@@ -109,7 +109,7 @@ class AuditoryRead(AuditoryBase):
id: int
class Config:
orm_mode = True
from_attributes = True
# === Zametka ===
@@ -125,7 +125,7 @@ class ZametkaRead(ZametkaBase):
created_date: Optional[datetime] = None
class Config:
orm_mode = True
from_attributes = True
# === Auth/User ===
@@ -151,8 +151,67 @@ class UserRead(UserBase):
id: int
class Config:
orm_mode = True
from_attributes = True
class UserRoleUpdate(BaseModel):
role: Role
# === Inspection System ===
# InspectionSession
class InspectionSessionBase(BaseModel):
aud_id: Optional[int] = None
class InspectionSessionCreate(InspectionSessionBase):
pass
class InspectionSessionRead(InspectionSessionBase):
id: int
user_id: int
started_at: datetime
completed_at: Optional[datetime] = None
class Config:
from_attributes = True
# InspectionRecord
class InspectionRecordRead(BaseModel):
id: int
session_id: int
oborud_id: int
checked_at: datetime
oborud: Optional[OborudRead] = None
class Config:
from_attributes = True
# UnknownBarcode
class UnknownBarcodeRead(BaseModel):
id: int
session_id: int
barcode: str
scanned_at: datetime
class Config:
from_attributes = True
# Ответ на сканирование
class CheckBarcodeResponse(BaseModel):
status: Literal["found", "not_found"]
equipment: Optional[OborudRead] = None
message: str
# Статистика сессии
class InspectionSessionStats(BaseModel):
session: InspectionSessionRead
total_expected: int # всего оборудования (в аудитории или всего)
total_checked: int # проверено уникальных позиций
total_unknown: int # неизвестных штрихкодов
progress_percent: float
# Детальный отчёт
class InspectionDetailReport(BaseModel):
records: List[InspectionRecordRead]
unknown_barcodes: List[UnknownBarcodeRead]

View File

@@ -5,6 +5,7 @@ const api = {
oboruds: (audId) => `/oboruds/?aud_id=${encodeURIComponent(audId)}`,
allOboruds: "/oboruds/?sort_by_inv=true",
owners: "/owners/",
zametki: "/zametki/",
};
async function fetchJSON(url) {
@@ -21,6 +22,8 @@ createApp({
selectedAudId: '',
oboruds: [],
allOboruds: [],
unassignedOboruds: [],
totalOboruds: 0,
status: '',
error: '',
printTitle: '',
@@ -33,6 +36,33 @@ createApp({
newAudName: '',
owners: [],
newOwnerName: '',
zametki: [],
newZametkaText: '',
equipmentTypes: [],
newTypeName: '',
newEquipment: {
invNumber: null,
nazvanie: '',
raspologenie: '',
kolichestvo: 1,
aud_id: '',
type_id: '',
owner_id: ''
},
// Inspection
activeInspection: null,
inspectionAudId: '',
scannedBarcode: '',
lastScanResult: null,
inspectionStats: {
total_checked: 0,
total_expected: 0,
total_unknown: 0,
progress_percent: 0
},
checkedEquipment: [],
unknownBarcodes: [],
inspectionHistory: []
};
},
computed: {
@@ -117,6 +147,27 @@ createApp({
this.view = 'allEquipment';
await this.loadAllOboruds();
},
async loadUnassigned() {
this.status = 'Загрузка нераспределённого оборудования…';
this.error = '';
try {
const [oboruds, stats] = await Promise.all([
fetchJSON('/oboruds/?unassigned=true&sort_by_inv=true'),
fetchJSON('/oboruds/stats')
]);
this.unassignedOboruds = oboruds;
this.totalOboruds = stats.total;
this.status = '';
} catch (e) {
console.error(e);
this.error = 'Не удалось загрузить данные';
this.status = '';
}
},
async showUnassigned() {
this.view = 'unassigned';
await this.loadUnassigned();
},
getAuditoryName(audId) {
if (!audId) return '';
const aud = this.auditories.find(a => a.id === audId);
@@ -129,6 +180,120 @@ createApp({
window.print();
});
},
printAllEquipment() {
window.print();
},
async loadZametki() {
this.status = 'Загрузка заметок…';
this.error = '';
try {
this.zametki = await fetchJSON(api.zametki);
this.status = '';
} catch (e) {
console.error(e);
this.error = 'Не удалось загрузить заметки';
this.status = '';
}
},
async showZametki() {
this.view = 'zametki';
await this.loadZametki();
},
async createZametka() {
if (!this.newZametkaText.trim()) {
this.status = 'Введите текст заметки';
return;
}
try {
this.status = 'Добавление заметки…';
await this.fetchAuth(api.zametki, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ txtzam: this.newZametkaText }),
});
this.newZametkaText = '';
await this.loadZametki();
this.status = 'Заметка добавлена';
} catch (e) {
console.error(e);
this.error = 'Не удалось добавить заметку';
this.status = '';
}
},
async resolveZametka(id) {
try {
this.status = 'Отметка заметки как решённой…';
await this.fetchAuth(`/zametki/${id}/resolve`, { method: 'PATCH' });
await this.loadZametki();
this.status = 'Заметка отмечена как решённая';
} catch (e) {
console.error(e);
this.error = 'Не удалось отметить заметку';
this.status = '';
}
},
formatDate(dateStr) {
if (!dateStr) return '';
const d = new Date(dateStr);
return d.toLocaleString('ru-RU');
},
async loadEquipmentTypes() {
try {
this.equipmentTypes = await fetchJSON('/equipment-types/');
} catch (e) {
console.error(e);
}
},
async createEquipmentType() {
if (!this.newTypeName.trim()) {
this.status = 'Введите название типа';
return;
}
try {
this.status = 'Добавление типа…';
await this.fetchAuth('/equipment-types/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: this.newTypeName }),
});
this.newTypeName = '';
await this.loadEquipmentTypes();
this.status = 'Тип добавлен';
} catch (e) {
console.error(e);
this.error = 'Не удалось добавить тип';
this.status = '';
}
},
async createEquipment() {
if (!this.newEquipment.nazvanie.trim()) {
this.status = 'Введите название оборудования';
return;
}
try {
this.status = 'Добавление оборудования…';
const data = {
nazvanie: this.newEquipment.nazvanie,
invNumber: this.newEquipment.invNumber || null,
raspologenie: this.newEquipment.raspologenie || null,
kolichestvo: this.newEquipment.kolichestvo || null,
aud_id: this.newEquipment.aud_id || null,
type_id: this.newEquipment.type_id || null,
owner_id: this.newEquipment.owner_id || null,
};
await this.fetchAuth('/oboruds/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
this.newEquipment = { invNumber: null, nazvanie: '', raspologenie: '', kolichestvo: 1, aud_id: '', type_id: '', owner_id: '' };
this.status = 'Оборудование добавлено';
} catch (e) {
console.error(e);
this.error = 'Не удалось добавить оборудование';
this.status = '';
}
},
async saveOwner(item) {
try {
this.status = 'Сохранение владельца…';
@@ -235,6 +400,187 @@ createApp({
this.error = 'Не удалось добавить аудиторию';
this.status = '';
}
},
// Inspection methods
async showInspection() {
this.view = 'inspection';
this.status = '';
this.error = '';
},
async startInspection() {
try {
this.status = 'Начало проверки…';
this.error = '';
const response = await this.fetchAuth('/inspections/sessions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
aud_id: this.inspectionAudId || null
})
});
this.activeInspection = response;
await this.loadInspectionStats();
this.status = 'Проверка начата';
// Фокус на поле ввода
this.$nextTick(() => {
if (this.$refs.barcodeInput) {
this.$refs.barcodeInput.focus();
}
});
} catch (e) {
console.error(e);
this.error = 'Не удалось начать проверку: ' + e.message;
this.status = '';
}
},
async checkBarcode() {
if (!this.scannedBarcode.trim()) return;
try {
this.status = 'Проверка штрихкода…';
const response = await this.fetchAuth(`/inspections/sessions/${this.activeInspection.id}/check`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
inv_number: this.scannedBarcode
})
});
this.lastScanResult = response;
// Очистить поле и обновить данные
this.scannedBarcode = '';
await this.loadInspectionStats();
await this.loadInspectionDetails();
this.status = '';
// Автоматически скрыть уведомление через 3 секунды
setTimeout(() => {
this.lastScanResult = null;
}, 3000);
// Вернуть фокус на поле ввода
this.$nextTick(() => {
if (this.$refs.barcodeInput) {
this.$refs.barcodeInput.focus();
}
});
} catch (e) {
console.error(e);
this.error = 'Не удалось проверить штрихкод: ' + e.message;
this.status = '';
}
},
async loadInspectionStats() {
try {
const response = await this.fetchAuth(`/inspections/sessions/${this.activeInspection.id}`);
this.inspectionStats = response;
} catch (e) {
console.error(e);
this.error = 'Не удалось загрузить статистику';
}
},
async loadInspectionDetails() {
try {
const response = await this.fetchAuth(`/inspections/sessions/${this.activeInspection.id}/records`);
this.checkedEquipment = response.records;
this.unknownBarcodes = response.unknown_barcodes;
} catch (e) {
console.error(e);
this.error = 'Не удалось загрузить детали проверки';
}
},
async refreshInspectionData() {
this.status = 'Обновление данных…';
await this.loadInspectionStats();
await this.loadInspectionDetails();
this.status = 'Данные обновлены';
},
async completeInspection() {
if (!confirm('Завершить проверку?')) return;
try {
this.status = 'Завершение проверки…';
await this.fetchAuth(`/inspections/sessions/${this.activeInspection.id}/complete`, {
method: 'POST'
});
this.activeInspection = null;
this.inspectionStats = {
total_checked: 0,
total_expected: 0,
total_unknown: 0,
progress_percent: 0
};
this.checkedEquipment = [];
this.unknownBarcodes = [];
this.lastScanResult = null;
this.status = 'Проверка завершена';
} catch (e) {
console.error(e);
this.error = 'Не удалось завершить проверку: ' + e.message;
this.status = '';
}
},
cancelInspection() {
if (confirm('Прервать проверку без сохранения?')) {
this.activeInspection = null;
this.inspectionStats = {
total_checked: 0,
total_expected: 0,
total_unknown: 0,
progress_percent: 0
};
this.checkedEquipment = [];
this.unknownBarcodes = [];
this.lastScanResult = null;
this.status = 'Проверка отменена';
}
},
async loadInspectionHistory() {
try {
this.status = 'Загрузка истории проверок…';
this.error = '';
this.inspectionHistory = await this.fetchAuth('/inspections/sessions');
this.status = `Загружено ${this.inspectionHistory.length} проверок`;
} catch (e) {
console.error(e);
this.error = 'Не удалось загрузить историю проверок: ' + e.message;
this.status = '';
}
},
async viewHistoryDetails(sessionId) {
try {
this.status = 'Загрузка деталей проверки…';
const [stats, details] = await Promise.all([
this.fetchAuth(`/inspections/sessions/${sessionId}`),
this.fetchAuth(`/inspections/sessions/${sessionId}/records`)
]);
// Показать активную проверку с данными истории
this.activeInspection = stats.session;
this.inspectionStats = stats;
this.checkedEquipment = details.records;
this.unknownBarcodes = details.unknown_barcodes;
this.status = '';
} catch (e) {
console.error(e);
this.error = 'Не удалось загрузить детали: ' + e.message;
this.status = '';
}
}
},
mounted() {
@@ -245,6 +591,7 @@ createApp({
} catch {}
this.loadAuditories();
this.loadOwners();
this.loadEquipmentTypes();
if (this.isAdmin) {
this.loadUsers();
}

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>АСУ Инвентаризация</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/app/bootstrap.min.css" />
<link rel="stylesheet" href="/app/styles.css" />
</head>
<body>
@@ -27,10 +27,23 @@
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item"><a class="nav-link" href="#" @click.prevent="view='byAud'">По аудитории</a></li>
<li class="nav-item"><a class="nav-link" href="#" @click.prevent="showAllEquipment">Всё оборудование</a></li>
<li class="nav-item"><a class="nav-link" href="#" @click.prevent="showUnassigned">Не распределено</a></li>
<li class="nav-item" v-if="isAuth"><a class="nav-link" href="#" @click.prevent="showInspection">Проверка</a></li>
<li class="nav-item" v-if="isAdmin"><a class="nav-link" href="#" @click.prevent="view='users'">Пользователи</a></li>
<li class="nav-item" v-if="isAdmin"><a class="nav-link" href="#" @click.prevent="view='audManage'">Аудитории</a></li>
<li class="nav-item"><a class="nav-link" href="/docs" target="_blank">API Docs</a></li>
<li class="nav-item" v-if="canEdit"><a class="nav-link" href="#" @click.prevent="view='owners'">Владельцы</a></li>
<li class="nav-item"><a class="nav-link" href="#" @click.prevent="showZametki">Заметки</a></li>
<li class="nav-item dropdown" v-if="canEdit">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">Добавить</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" @click.prevent="view='addEquipment'">Оборудование</a></li>
<li><a class="dropdown-item" href="#" @click.prevent="view='addAuditory'">Аудиторию</a></li>
<li><a class="dropdown-item" href="#" @click.prevent="view='addType'">Тип оборудования</a></li>
<li><a class="dropdown-item" href="#" @click.prevent="view='addOwner'">Владельца</a></li>
<li v-if="isAdmin"><hr class="dropdown-divider"></li>
<li v-if="isAdmin"><a class="dropdown-item" href="#" @click.prevent="view='addUser'">Пользователя</a></li>
</ul>
</li>
<li class="nav-item" v-if="isAuth"><a class="nav-link" href="/docs" target="_blank">API Docs</a></li>
</ul>
<span class="navbar-text ms-auto" v-if="isAuth">Роль: {{ role }}</span>
<a class="btn btn-outline-primary ms-2" v-if="!isAuth" href="/login">Войти</a>
@@ -46,8 +59,8 @@
<div class="card-body">
<h3 class="card-title no-print">Оборудование по аудитории</h3>
<h2 class="print-only print-title">{{ printTitle }}</h2>
<div class="mb-2 d-flex align-items-center gap-2 no-print">
<label for="aud-select" class="me-2">Аудитория:</label>
<div class="mb-2 d-flex align-items-center justify-content-center gap-2 no-print">
<label for="aud-select" class="mb-0">Аудитория:</label>
<select id="aud-select" class="form-select w-auto" v-model="selectedAudId">
<option value="">— выберите аудиторию —</option>
<option v-for="a in auditories" :key="a.id" :value="a.id">{{ a.audnazvanie }}</option>
@@ -102,30 +115,34 @@
<div v-if="view==='allEquipment'" class="row">
<div class="card col-12">
<div class="card-body">
<h3 class="card-title">Всё оборудование (по инв. номеру)</h3>
<div class="status" :class="{error: !!error}">{{ status }}</div>
<h3 class="card-title no-print">Всё оборудование (по инв. номеру)</h3>
<h2 class="print-only print-title">Всё оборудование</h2>
<div class="mb-2 no-print">
<button class="btn btn-secondary" @click="printAllEquipment" :disabled="!allOboruds.length">Печать</button>
</div>
<div class="status no-print" :class="{error: !!error}">{{ status }}</div>
<div class="table-responsive">
<table class="table datatable">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Инв. номер</th>
<th scope="col" class="num-col"></th>
<th scope="col" class="inv-col">Инв. номер</th>
<th scope="col">Название</th>
<th scope="col">Аудитория</th>
<th scope="col" class="aud-col">Аудитория</th>
<th scope="col">Расположение</th>
<th scope="col">Кол-во</th>
<th scope="col">Владелец</th>
<th scope="col" class="no-print">Кол-во</th>
<th scope="col" class="no-print">Владелец</th>
</tr>
</thead>
<tbody>
<tr v-for="(it, index) in allOboruds" :key="it.id">
<td>{{ index + 1 }}</td>
<td class="inv">{{ it.invNumber ?? '' }}</td>
<td class="num-col">{{ index + 1 }}</td>
<td class="inv-col">{{ it.invNumber ?? '' }}</td>
<td>{{ it.nazvanie ?? '' }}</td>
<td>{{ getAuditoryName(it.aud_id) }}</td>
<td class="aud-col">{{ getAuditoryName(it.aud_id) }}</td>
<td class="rasp">{{ it.raspologenie ?? '' }}</td>
<td>{{ it.kolichestvo ?? '' }}</td>
<td>{{ it.owner?.name ?? '' }}</td>
<td class="no-print">{{ it.kolichestvo ?? '' }}</td>
<td class="no-print">{{ it.owner?.name ?? '' }}</td>
</tr>
</tbody>
</table>
@@ -261,9 +278,357 @@
</div>
</div>
</div>
<div v-if="view==='unassigned'" class="row">
<div class="card col-12">
<div class="card-body">
<h3 class="card-title">Не распределено: {{ unassignedOboruds.length }} из {{ totalOboruds }}</h3>
<div class="status" :class="{error: !!error}">{{ status }}</div>
<div class="table-responsive">
<table class="table datatable">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
<th scope="col">Владелец</th>
</tr>
</thead>
<tbody>
<tr v-for="(it, index) in unassignedOboruds" :key="it.id">
<td>{{ index + 1 }}</td>
<td class="inv">{{ it.invNumber ?? '' }}</td>
<td>{{ it.nazvanie ?? '' }}</td>
<td>{{ it.owner?.name ?? '' }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div v-if="view==='zametki'" class="row">
<div class="card col-12">
<div class="card-body">
<h3 class="card-title">Заметки</h3>
<div v-if="canEdit" class="mb-4">
<h5>Добавить заметку</h5>
<div class="row g-2 align-items-end">
<div class="col-md-8">
<textarea class="form-control" v-model="newZametkaText" rows="3" placeholder="Текст заметки..."></textarea>
</div>
<div class="col-auto">
<button class="btn btn-success" @click="createZametka">Добавить</button>
</div>
</div>
</div>
<div class="status" :class="{error: !!error}">{{ status }}</div>
<h5>Активные заметки</h5>
<div v-if="zametki.length === 0" class="text-muted">Нет активных заметок</div>
<div v-for="z in zametki" :key="z.id" class="card mb-2">
<div class="card-body">
<p class="card-text" style="white-space: pre-wrap;">{{ z.txtzam }}</p>
<small class="text-muted">{{ formatDate(z.created_date) }}</small>
<button v-if="canEdit" class="btn btn-sm btn-outline-success float-end" @click="resolveZametka(z.id)">Решено</button>
</div>
</div>
</div>
</div>
</div>
<!-- Добавить оборудование -->
<div v-if="view==='addEquipment'" class="row">
<div class="card col-12 col-md-8">
<div class="card-body">
<h3 class="card-title">Добавить оборудование</h3>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label">Инв. номер</label>
<input type="number" class="form-control" v-model="newEquipment.invNumber" />
</div>
<div class="col-md-8">
<label class="form-label">Название</label>
<input type="text" class="form-control" v-model="newEquipment.nazvanie" required />
</div>
<div class="col-md-4">
<label class="form-label">Аудитория</label>
<select class="form-select" v-model="newEquipment.aud_id">
<option value="">— не выбрано —</option>
<option v-for="a in auditories" :key="a.id" :value="a.id">{{ a.audnazvanie }}</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Тип</label>
<select class="form-select" v-model="newEquipment.type_id">
<option value="">— не выбрано —</option>
<option v-for="t in equipmentTypes" :key="t.id" :value="t.id">{{ t.name }}</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Владелец</label>
<select class="form-select" v-model="newEquipment.owner_id">
<option value="">— не выбрано —</option>
<option v-for="o in owners" :key="o.id" :value="o.id">{{ o.name }}</option>
</select>
</div>
<div class="col-md-8">
<label class="form-label">Расположение</label>
<input type="text" class="form-control" v-model="newEquipment.raspologenie" />
</div>
<div class="col-md-4">
<label class="form-label">Количество</label>
<input type="number" class="form-control" v-model="newEquipment.kolichestvo" />
</div>
</div>
<div class="status mt-3" :class="{error: !!error}">{{ status }}</div>
<button class="btn btn-success mt-3" @click="createEquipment">Добавить</button>
</div>
</div>
</div>
<!-- Добавить аудиторию -->
<div v-if="view==='addAuditory'" class="row">
<div class="card col-12 col-md-6">
<div class="card-body">
<h3 class="card-title">Добавить аудиторию</h3>
<div class="mb-3">
<label class="form-label">Название аудитории</label>
<input type="text" class="form-control" v-model="newAudName" placeholder="например, 519" />
</div>
<div class="status" :class="{error: !!error}">{{ status }}</div>
<button class="btn btn-success" @click="createAuditory">Добавить</button>
</div>
</div>
</div>
<!-- Добавить тип оборудования -->
<div v-if="view==='addType'" class="row">
<div class="card col-12 col-md-6">
<div class="card-body">
<h3 class="card-title">Добавить тип оборудования</h3>
<div class="mb-3">
<label class="form-label">Название типа</label>
<input type="text" class="form-control" v-model="newTypeName" placeholder="например, Компьютер" />
</div>
<div class="status" :class="{error: !!error}">{{ status }}</div>
<button class="btn btn-success" @click="createEquipmentType">Добавить</button>
<h5 class="mt-4">Существующие типы</h5>
<ul class="list-group">
<li class="list-group-item" v-for="t in equipmentTypes" :key="t.id">{{ t.name }}</li>
</ul>
</div>
</div>
</div>
<!-- Добавить владельца -->
<div v-if="view==='addOwner'" class="row">
<div class="card col-12 col-md-6">
<div class="card-body">
<h3 class="card-title">Добавить владельца</h3>
<div class="mb-3">
<label class="form-label">Имя владельца</label>
<input type="text" class="form-control" v-model="newOwnerName" placeholder="например, Иванов И.И." />
</div>
<div class="status" :class="{error: !!error}">{{ status }}</div>
<button class="btn btn-success" @click="createOwner">Добавить</button>
<h5 class="mt-4">Существующие владельцы</h5>
<ul class="list-group">
<li class="list-group-item" v-for="o in owners" :key="o.id">{{ o.name }}</li>
</ul>
</div>
</div>
</div>
<!-- Добавить пользователя -->
<div v-if="view==='addUser'" class="row">
<div class="card col-12 col-md-6">
<div class="card-body">
<h3 class="card-title">Добавить пользователя</h3>
<div class="mb-3">
<label class="form-label">Логин</label>
<input type="text" class="form-control" v-model="newAdminUsername" />
</div>
<div class="mb-3">
<label class="form-label">Пароль</label>
<input type="password" class="form-control" v-model="newAdminPassword" />
</div>
<div class="status" :class="{error: !!error}">{{ status }}</div>
<button class="btn btn-success" @click="createAdmin">Создать администратора</button>
</div>
</div>
</div>
<!-- Проверка оборудования -->
<div v-if="view==='inspection'" class="row">
<div class="card col-12">
<div class="card-body">
<h3 class="card-title">Проверка оборудования</h3>
<!-- Блок 1: Начать проверку (если нет активной сессии) -->
<div v-if="!activeInspection">
<h5>Начать новую проверку</h5>
<div class="row g-2 align-items-end mb-3">
<div class="col-auto">
<label class="form-label">Аудитория (необязательно)</label>
<select class="form-select" v-model="inspectionAudId">
<option value="">— Всё оборудование —</option>
<option v-for="a in auditories" :key="a.id" :value="a.id">{{ a.audnazvanie }}</option>
</select>
</div>
<div class="col-auto">
<button class="btn btn-success" @click="startInspection">Начать проверку</button>
</div>
</div>
<h5 class="mt-4">История проверок</h5>
<button class="btn btn-secondary mb-3" @click="loadInspectionHistory">Загрузить историю</button>
<div v-if="inspectionHistory.length > 0" class="table-responsive">
<table class="table datatable">
<thead>
<tr>
<th>ID</th>
<th>Начата</th>
<th>Завершена</th>
<th>Аудитория</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
<tr v-for="sess in inspectionHistory" :key="sess.id">
<td>{{ sess.id }}</td>
<td>{{ formatDate(sess.started_at) }}</td>
<td>{{ sess.completed_at ? formatDate(sess.completed_at) : '—' }}</td>
<td>{{ sess.aud_id ? getAuditoryName(sess.aud_id) : 'Всё' }}</td>
<td>
<button class="btn btn-sm btn-primary" @click="viewHistoryDetails(sess.id)">Детали</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Блок 2: Активная проверка -->
<div v-else>
<div class="alert alert-info">
<strong>Активная проверка</strong><br>
<span v-if="activeInspection.aud_id">Аудитория: {{ getAuditoryName(activeInspection.aud_id) }}</span>
<span v-else>Всё оборудование</span><br>
Начата: {{ formatDate(activeInspection.started_at) }}
</div>
<!-- Статистика прогресса -->
<div class="row mb-3">
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">{{ inspectionStats.total_checked }}</h5>
<p class="card-text">Проверено</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">{{ inspectionStats.total_expected }}</h5>
<p class="card-text">Всего</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">{{ inspectionStats.total_unknown }}</h5>
<p class="card-text">Не найдено</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center bg-success text-white">
<div class="card-body">
<h5 class="card-title">{{ inspectionStats.progress_percent }}%</h5>
<p class="card-text">Прогресс</p>
</div>
</div>
</div>
</div>
<!-- Поле для сканирования -->
<div class="mb-3">
<label class="form-label">Сканируйте штрихкод или введите инв. номер</label>
<input
ref="barcodeInput"
type="text"
class="form-control form-control-lg"
v-model="scannedBarcode"
@keyup.enter="checkBarcode"
placeholder="Отсканируйте или введите номер..."
autofocus
/>
</div>
<!-- Последний результат сканирования -->
<div v-if="lastScanResult" class="alert" :class="lastScanResult.status === 'found' ? 'alert-success' : 'alert-danger'">
{{ lastScanResult.message }}
<div v-if="lastScanResult.equipment">
<strong>{{ lastScanResult.equipment.nazvanie }}</strong>
</div>
</div>
<!-- Кнопки действий -->
<div class="mt-3 mb-4">
<button class="btn btn-primary me-2" @click="refreshInspectionData">Обновить данные</button>
<button class="btn btn-success me-2" @click="completeInspection">Завершить проверку</button>
<button class="btn btn-secondary" @click="cancelInspection">Отменить</button>
</div>
<!-- Таблица проверенного оборудования (в реальном времени) -->
<h5 class="mt-4">Проверенное оборудование</h5>
<div class="table-responsive">
<table class="table datatable">
<thead>
<tr>
<th>Инв. номер</th>
<th>Название</th>
<th>Аудитория</th>
<th>Проверено</th>
</tr>
</thead>
<tbody>
<tr v-for="rec in checkedEquipment" :key="rec.id">
<td>{{ rec.oborud?.invNumber }}</td>
<td>{{ rec.oborud?.nazvanie }}</td>
<td>{{ getAuditoryName(rec.oborud?.aud_id) }}</td>
<td>{{ formatDate(rec.checked_at) }}</td>
</tr>
</tbody>
</table>
</div>
<!-- Неизвестные штрихкоды -->
<div v-if="unknownBarcodes.length > 0">
<h5 class="mt-4 text-danger">Неизвестные штрихкоды</h5>
<ul class="list-group">
<li class="list-group-item" v-for="ub in unknownBarcodes" :key="ub.id">
{{ ub.barcode }} — {{ formatDate(ub.scanned_at) }}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="/app/app.js" defer></script>
</body>
</html>

View File

@@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Вход — АСУ Инвентаризация</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/index.css" />
<link rel="stylesheet" href="/app/bootstrap.min.css" />
<link rel="stylesheet" href="/app/styles.css" />
<style>
.login-card { max-width: 420px; margin: 40px auto; }
.muted { color: #6c757d; font-size: 0.9rem; }

View File

@@ -75,6 +75,23 @@ table {
width: 110px;
}
td.aud-col, th.aud-col {
width: 70px;
min-width: 70px;
max-width: 70px;
}
td.num-col, th.num-col {
width: 40px;
min-width: 40px;
max-width: 40px;
text-align: center;
}
td.inv-col, th.inv-col {
width: auto;
}
.inv {
width: 400px;
}
@@ -169,6 +186,16 @@ table {
border: 1px solid #000000;
padding: 5px;
font-size: 12pt;
word-break: normal;
word-wrap: break-word;
overflow-wrap: break-word;
white-space: normal;
}
td.inv-col, th.inv-col {
width: 100px;
min-width: 100px;
max-width: 100px;
}
table.rs-table-bordered {

View File

@@ -1 +0,0 @@
Single-database configuration for Flask.

View File

@@ -1,52 +0,0 @@
# A generic, single database configuration.
[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
script_location = .
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic,flask_migrate
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[logger_flask_migrate]
level = INFO
handlers =
qualname = flask_migrate
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

View File

@@ -1,113 +0,0 @@
import logging
from logging.config import fileConfig
from flask import current_app
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
def get_engine():
try:
# this works with Flask-SQLAlchemy<3 and Alchemical
return current_app.extensions['migrate'].db.get_engine()
except (TypeError, AttributeError):
# this works with Flask-SQLAlchemy>=3
return current_app.extensions['migrate'].db.engine
def get_engine_url():
try:
return get_engine().url.render_as_string(hide_password=False).replace(
'%', '%%')
except AttributeError:
return str(get_engine().url).replace('%', '%%')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
config.set_main_option('sqlalchemy.url', get_engine_url())
target_db = current_app.extensions['migrate'].db
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def get_metadata():
if hasattr(target_db, 'metadatas'):
return target_db.metadatas[None]
return target_db.metadata
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=get_metadata(), literal_binds=True
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
conf_args = current_app.extensions['migrate'].configure_args
if conf_args.get("process_revision_directives") is None:
conf_args["process_revision_directives"] = process_revision_directives
connectable = get_engine()
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=get_metadata(),
**conf_args
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

View File

@@ -1,24 +0,0 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

View File

@@ -1,32 +0,0 @@
"""empty message
Revision ID: 10da3140ab2e
Revises: 4eacd6dcd461
Create Date: 2024-04-05 01:25:48.931573
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '10da3140ab2e'
down_revision = '4eacd6dcd461'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('kolichestvo', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('kolichestvo')
# ### end Alembic commands ###

View File

@@ -1,32 +0,0 @@
"""empty message
Revision ID: 256c3a3e91a2
Revises: 4f95d12a8352
Create Date: 2024-03-13 16:01:01.559719
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '256c3a3e91a2'
down_revision = '4f95d12a8352'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('somepl')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('somepl', sa.VARCHAR(length=10), nullable=True))
# ### end Alembic commands ###

View File

@@ -1,54 +0,0 @@
"""empty message
Revision ID: 4eacd6dcd461
Revises: c208cbc25232
Create Date: 2024-04-03 23:25:42.271936
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4eacd6dcd461'
down_revision = 'c208cbc25232'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('numberved', sa.String(length=100), nullable=True))
batch_op.add_column(sa.Column('numberppasu', sa.String(length=100), nullable=True))
batch_op.add_column(sa.Column('balancenumber', sa.Integer(), nullable=True))
batch_op.alter_column('nazvanie',
existing_type=sa.TEXT(length=500),
type_=sa.String(length=500),
existing_nullable=True)
batch_op.alter_column('raspologenie',
existing_type=sa.TEXT(length=200),
type_=sa.String(length=200),
existing_nullable=True)
batch_op.drop_column('buhnumberpp')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('buhnumberpp', sa.VARCHAR(length=100), nullable=True))
batch_op.alter_column('raspologenie',
existing_type=sa.String(length=200),
type_=sa.TEXT(length=200),
existing_nullable=True)
batch_op.alter_column('nazvanie',
existing_type=sa.String(length=500),
type_=sa.TEXT(length=500),
existing_nullable=True)
batch_op.drop_column('balancenumber')
batch_op.drop_column('numberppasu')
batch_op.drop_column('numberved')
# ### end Alembic commands ###

View File

@@ -1,32 +0,0 @@
"""empty message
Revision ID: 4f95d12a8352
Revises: 50f85881169e
Create Date: 2024-03-13 15:57:33.119683
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4f95d12a8352'
down_revision = '50f85881169e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('somepl', sa.String(length=10), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('somepl')
# ### end Alembic commands ###

View File

@@ -1,24 +0,0 @@
"""empty message
Revision ID: 50f85881169e
Revises: b24baa0d98e6
Create Date: 2024-03-13 15:55:03.770084
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '50f85881169e'
down_revision = 'b24baa0d98e6'
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass

View File

@@ -1,34 +0,0 @@
"""empty message
Revision ID: 6fc3d1adb061
Revises: be7c94c549e5
Create Date: 2024-04-02 16:32:23.180273
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '6fc3d1adb061'
down_revision = 'be7c94c549e5'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('buhnumberpp', sa.String(length=100), nullable=True))
batch_op.add_column(sa.Column('kolichestvo', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('kolichestvo')
batch_op.drop_column('buhnumberpp')
# ### end Alembic commands ###

View File

@@ -1,32 +0,0 @@
"""empty message
Revision ID: 873defe09f22
Revises: ec6bbcd361bd
Create Date: 2024-03-13 22:34:36.718676
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '873defe09f22'
down_revision = 'ec6bbcd361bd'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('raspologenie', sa.String(length=200), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('raspologenie')
# ### end Alembic commands ###

View File

@@ -1,32 +0,0 @@
"""empty message
Revision ID: 885bdd7b5161
Revises: be7c94c549e5
Create Date: 2024-04-02 23:03:59.401369
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '885bdd7b5161'
down_revision = 'be7c94c549e5'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('kolichestvo', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('kolichestvo')
# ### end Alembic commands ###

View File

@@ -1,54 +0,0 @@
"""empty message
Revision ID: 8e5efc4de919
Revises: c208cbc25232
Create Date: 2024-04-03 22:36:46.208266
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '8e5efc4de919'
down_revision = 'c208cbc25232'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('numberved', sa.String(length=100), nullable=True))
batch_op.add_column(sa.Column('numberppasu', sa.String(length=100), nullable=True))
batch_op.add_column(sa.Column('balancenumber', sa.Integer(), nullable=True))
batch_op.alter_column('nazvanie',
existing_type=sa.TEXT(length=500),
type_=sa.String(length=500),
existing_nullable=True)
batch_op.alter_column('raspologenie',
existing_type=sa.TEXT(length=200),
type_=sa.String(length=200),
existing_nullable=True)
batch_op.drop_column('buhnumberpp')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('buhnumberpp', sa.TEXT(length=100), nullable=True))
batch_op.alter_column('raspologenie',
existing_type=sa.String(length=200),
type_=sa.TEXT(length=200),
existing_nullable=True)
batch_op.alter_column('nazvanie',
existing_type=sa.String(length=500),
type_=sa.TEXT(length=500),
existing_nullable=True)
batch_op.drop_column('balancenumber')
batch_op.drop_column('numberppasu')
batch_op.drop_column('numberved')
# ### end Alembic commands ###

View File

@@ -1,32 +0,0 @@
"""empty message
Revision ID: 8e838956713f
Revises: 256c3a3e91a2
Create Date: 2024-03-20 19:03:51.112016
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '8e838956713f'
down_revision = '256c3a3e91a2'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('numberved', sa.String(length=100), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('numberved')
# ### end Alembic commands ###

View File

@@ -1,24 +0,0 @@
"""empty message
Revision ID: b24baa0d98e6
Revises: 873defe09f22, b2a61aef79e9
Create Date: 2024-03-13 15:42:47.733687
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'b24baa0d98e6'
down_revision = ('873defe09f22', 'b2a61aef79e9')
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass

View File

@@ -1,24 +0,0 @@
"""empty message
Revision ID: b2a61aef79e9
Revises: ec6bbcd361bd
Create Date: 2024-03-13 01:48:30.093937
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'b2a61aef79e9'
down_revision = 'ec6bbcd361bd'
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass

View File

@@ -1,34 +0,0 @@
"""empty message
Revision ID: be7c94c549e5
Revises: 8e838956713f
Create Date: 2024-04-01 15:09:52.082987
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'be7c94c549e5'
down_revision = '8e838956713f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('balancenumber', sa.String(length=30), nullable=True))
batch_op.drop_column('typeBalanse')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('typeBalanse', sa.VARCHAR(length=30), nullable=True))
batch_op.drop_column('balancenumber')
# ### end Alembic commands ###

View File

@@ -1,24 +0,0 @@
"""empty message
Revision ID: c208cbc25232
Revises: 6fc3d1adb061, 885bdd7b5161
Create Date: 2024-04-03 22:11:15.008480
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c208cbc25232'
down_revision = ('6fc3d1adb061', '885bdd7b5161')
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass

View File

@@ -1,24 +0,0 @@
"""empty message
Revision ID: d4a8e4c9e65a
Revises: 10da3140ab2e, 8e5efc4de919
Create Date: 2024-05-06 08:27:39.088982
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'd4a8e4c9e65a'
down_revision = ('10da3140ab2e', '8e5efc4de919')
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass

View File

@@ -1,44 +0,0 @@
"""empty message
Revision ID: ec6bbcd361bd
Revises:
Create Date: 2024-03-13 08:22:23.761783
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'ec6bbcd361bd'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.drop_column('duplicate')
with op.batch_alter_table('zametki', schema=None) as batch_op:
batch_op.alter_column('txtzam',
existing_type=sa.TEXT(length=10000),
type_=sa.String(length=10000),
existing_nullable=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('zametki', schema=None) as batch_op:
batch_op.alter_column('txtzam',
existing_type=sa.String(length=10000),
type_=sa.TEXT(length=10000),
existing_nullable=True)
with op.batch_alter_table('oboruds', schema=None) as batch_op:
batch_op.add_column(sa.Column('duplicate', sa.BOOLEAN(), nullable=True))
# ### end Alembic commands ###

View File

@@ -1,76 +0,0 @@
# backend/models.py
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime
from sqlalchemy.orm import relationship, declarative_base
import datetime
Base = declarative_base()
class Auditory(Base):
__tablename__ = 'auditories'
id = Column(Integer, primary_key=True)
audnazvanie = Column(String)
oboruds = relationship("Oboruds", back_populates="auditory")
class EquipmentType(Base):
__tablename__ = 'equipment_types'
id = Column(Integer, primary_key=True)
name = Column(String, unique=True, nullable=False)
oboruds = relationship("Oboruds", back_populates="type")
class Oboruds(Base):
__tablename__ = 'oboruds'
id = Column(Integer, primary_key=True)
invNumber = Column(Integer)
nazvanie = Column(String(500))
raspologenie = Column(String(200))
numberppasu = Column(String(100))
kolichestvo = Column(Integer)
aud_id = Column(Integer, ForeignKey("auditories.id"))
auditory = relationship("Auditory", back_populates="oboruds")
type_id = Column(Integer, ForeignKey("equipment_types.id"))
type = relationship("EquipmentType", back_populates="oboruds")
components = relationship("Component", back_populates="oborud")
consumables = relationship("Consumable", back_populates="oborud")
class Component(Base):
__tablename__ = 'components'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
description = Column(String)
oborud_id = Column(Integer, ForeignKey("oboruds.id"))
oborud = relationship("Oboruds", back_populates="components")
class Consumable(Base):
__tablename__ = 'consumables'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
description = Column(String)
oborud_id = Column(Integer, ForeignKey("oboruds.id"))
oborud = relationship("Oboruds", back_populates="consumables")
class Zametki(Base):
__tablename__ = 'zametki'
id = Column(Integer, primary_key=True)
txtzam = Column(String(10000))
created_date = Column(DateTime, default=datetime.datetime.utcnow)
rmdt = Column(DateTime)

View File

@@ -23,6 +23,7 @@ Flask-SQLAlchemy==3.1.1
waitress==3.0.2
# Auth
python-jose==3.3.0
python-jose==3.5.0
passlib==1.7.4
bcrypt==4.2.0
bcrypt==5.0.0
python-multipart==0.0.28

View File

@@ -1,6 +0,0 @@
from waitress import serve
from app import app
if __name__ == '__main__':
serve(app, port='3800')

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,179 +0,0 @@
* {
margin: 0;
padding: 0;
}
body {
background-color: #E2F3FD;
min-width: 580px;
}
.row {
text-align: center;
display: flex;
justify-content: center;
border: 1px;
}
header {
text-align: center;
background-color: #6A90B6;
padding: 2px;
}
a:hover {
text-decoration: none;
color: #041322;
}
a {
color: #041322;
}
.container {
margin: 10px;
}
button {
background-color: #E07D54;
margin-top: 5px;
margin-bottom: 5px;
}
.card {
/*width: 200px; */
margin: 10px;
border-radius: 15px;
border-color: #E07D54;
}
h5 {
text-align: center;
}
.hidden-column {
display: none;
}
nav {
width: 100%;
}
table {
word-break: break-all;
border-collapse: separate !important;
}
.table td {
font-size: 14px;
padding: 0;
max-width: 10rem;
word-break: break-all;
border-collapse: separate !important;
}
.aud {
width: 110px;
}
.inv {
width: 400px;
}
.rasp {
width: 200px;
word-break: break-word;
white-space: nowrap;
}
#modal_matcenn {
margin-left: 20px;
}
.datatable {
background-color: whitesmoke;
}
.datatable th:nth-child(7) {
width: 200px;
}
@media print {
* {
font-family: "Times New Roman", Times, serif;
}
body {
margin: 0;
padding: 0;
background-color: transparent;
}
a {
text-decoration: none;
border: none;
}
@page {
size: A4; /* или letter, legal, tabloid, etc. */
margin: 1cm; /* Устанавливаем поля */
align-items: center;
}
.card {
border: none;
width: 100%;
}
.no-print {
display: none;
}
table.rs-table-bordered {
border: 1px solid #000000;
margin-top: 20px;
font-size: 14pt;
}
table.rs-table-bordered > thead > tr > th {
border: 1px solid #000000;
padding: 2px;
font-size: 14pt;
}
table.rs-table-bordered > tbody > tr > td {
border: 1px solid #000000;
padding: 10px;
font-size: 14pt;
}
}

View File

@@ -1,282 +0,0 @@
function clearTable() {
var table = document.getElementById("alldatatable");
var rowCount = table.rows.length;
// Iterate through each row and remove it
for (var i = rowCount - 1; i > 0; i--) {
table.deleteRow(i);
}
}
function getAllData() {
clearTable();
let tableBody = document.getElementById('alldatatable').getElementsByTagName("tbody")[0];
i = 0;
$.getJSON("/getall", function (data) {
$.each(data, function (index, item) {
let newRow = tableBody.insertRow(tableBody.rows.length);
let cell1 = newRow.insertCell(0);
let cell2 = newRow.insertCell(1);
let cell3 = newRow.insertCell(2);
let cell4 = newRow.insertCell(3);
let cell5 = newRow.insertCell(4);
let cell6 = newRow.insertCell(5);
let cell7 = newRow.insertCell(6);
let cell8 = newRow.insertCell(7);
i++;
cell1.innerText = i;
cell2.innerText = item.numberved;
cell3.innerText = item.invNumber;
cell4.innerText = item.nazvanie;
cell5.innerText = item.kolichestvo;
cell6.innerText = item.balancenumber;
cell7.innerText = item.aud;
cell8.innerText = item.raspologenie;
$(newRow).data('itemData', i);
$(newRow).on("click", function () {
let vednumbertxt = newRow.cells[1].innerText;
let invnomertxt = newRow.cells[2].innerText;
let nazvanietxt = newRow.cells[3].innerText;
let kolvotxt = newRow.cells[4].innerText;
let schettxt = newRow.cells[5].innerText;
let raspologtxt = newRow.cells[7].innerText;
$('#getmodal').modal('show');
let vedomost = document.getElementById('modal_vednumber')
let invnom = document.getElementById('modal_invnom')
let matcen = document.getElementById('modal_matcenn')
let kolvo = document.getElementById('modal_kolvo')
let balancenumber = document.getElementById('modal_balance')
let rasp = document.getElementById('modal_rapolog')
invnom.innerText = invnomertxt
matcen.innerText = nazvanietxt.substring(0, 20)
if (vednumbertxt.length > 0) {
vedomost.value = vednumbertxt;
}
if (kolvotxt.length > 0) {
kolvo.value = kolvotxt;
}
if (schettxt.length > 0) {
balancenumber.value = schettxt;
}
if (raspologtxt.length > 0) {
rasp.value = raspologtxt;
}
});
});
});
}
$(document).ready(function () {
getAllData();
});
$('#modalclose').click(function () {
let vednumber = document.getElementById('modal_vednumber')
let kolvo = document.getElementById('modal_kolvo')
let balancenumber = document.getElementById('modal_balance')
let matcen = document.getElementById('modal_matcenn')
let rasp = document.getElementById('modal_rapolog')
vednumber.value = '';
kolvo.value = '';
balancenumber.value = '';
matcen.value = '';
rasp.value = '';
$('#getmodal').modal('hide')
})
$('#modalsavetodb').click(function () {
let invnom = document.getElementById('modal_invnom')
let vednumber = document.getElementById('modal_vednumber')
let kolvo = document.getElementById('modal_kolvo')
let balancenumber = document.getElementById('modal_balance')
let matcen = document.getElementById('modal_matcenn')
let rasp = document.getElementById('modal_rapolog')
let nazv = document.getElementById('modal_nazvanie')
let changeddata = new Array()
changeddata[0] = invnom.text;
changeddata[1] = vednumber.value;
changeddata[2] = kolvo.value;
changeddata[3] = balancenumber.value;
changeddata[4] = rasp.value;
let sendData = changeddata.join(',')
console.log(sendData)
$.ajax({
url: "/addraspved",
type: "POST",
contentType: "application/json;charset=utf-8",
dataType: "json",
data: sendData,
success: function () {
$('#getmodal').modal('hide')
vednumber.value = '';
kolvo.value = '';
balancenumber.value = '';
matcen.value = '';
rasp.value = '';
changeddata = [];
window.location.reload();
},
})
})
$('#addoborud').click(function () {
$('#addmodal').modal('show');
})
$('#modal2savetodb').click(function () {
let invnomer = document.getElementById('modal2_invnom')
let vednumber = document.getElementById('modal2_vednumber')
let kolvo = document.getElementById('modal2_kolvo')
let balancenumber = document.getElementById('modal2_balance')
let matcen = document.getElementById('modal2_matcenn')
let rasp = document.getElementById('modal2_rapolog')
let nazv = document.getElementById('modal2_nazvanie')
let changeddata = new Array()
changeddata[0] = invnomer.value;
changeddata[1] = vednumber.value;
changeddata[2] = kolvo.value;
changeddata[3] = balancenumber.value;
changeddata[4] = rasp.value;
changeddata[5] = nazv.value;
let sendData = changeddata.join(',')
console.log(sendData)
$.ajax({
url: "/addoborudasu",
type: "POST",
contentType: "application/json;charset=utf-8",
dataType: "json",
data: sendData,
success: function () {
vednumber.value = '';
invnomer.value = '';
nazvanie.value = '';
kolvo.value = '';
balancenumber.value = '';
matcen.value = '';
rasp.value = '';
$('#addmodal').modal('hide')
window.location.reload()
},
})
})
$('#modal2close').click(function () {
let vednumber = document.getElementById('modal2_vednumber')
let invnomer = document.getElementById('modal2_invnom')
let nazvanie = document.getElementById('modal2_nazvanie')
let kolvo = document.getElementById('modal2_kolvo')
let balancenumber = document.getElementById('modal2_balance')
let matcen = document.getElementById('modal2_matcenn')
let rasp = document.getElementById('modal2_rapolog')
vednumber.value = '';
invnomer.value = '';
nazvanie.value = '';
kolvo.value = '';
balancenumber.value = '';
matcen.value = '';
rasp.value = '';
$('#addmodal').modal('hide')
})
$('#modal2').on('hidden.bs.modal', function () {
location.reload();
})
$(document).ready(function () {
// Слушаем событие клика по заголовкам таблицы
$('#alldatatable thead th').on('click', function () {
var columnIndex = $(this).index(); // Индекс колонки
var sortColumn = $(this).text().toLowerCase(); // Текст заголовка колонки
// Сортируем таблицу по выбранной колонке
$('#alldatatable tbody tr').sort(function (a, b) {
var valA;
var valB;
if (isNaN(parseFloat($(a).find('td:eq(' + columnIndex + ')').text()))) {
// если это текстовая колонка, то сортируем по алфавиту
valA = $(a).find('td:eq(' + columnIndex + ')').text().toLowerCase();
valB = $(b).find('td:eq(' + columnIndex + ')').text().toLowerCase();
} else {
// если это числовая колонка, то сортируем по числовому значению
valA = parseFloat($(a).find('td:eq(' + columnIndex + ')').text());
valB = parseFloat($(b).find('td:eq(' + columnIndex + ')').text());
}
if (valA < valB) return -1;
if (valA > valB) return 1;
return 0;
}).appendTo('#alldatatable tbody');
// Обновляем классы для активной колонки
$('#alldatatable thead th').removeClass('active');
$(this).addClass('active');
});
});

View File

@@ -1,35 +0,0 @@
function getData(){
const audid = document.getElementById('auditory')
$.ajax({
url: "/getall",
type: "get",
contentType: 'application/json',
dataType: 'json',
success: function(response){
var data = response;
const table = document.getElementById('datatable')
table.innerHTML = ''
var headTable = '<tr> <td >Номер в Инв. вед</td> <td id="invnomer">Инв. номер</td><td>Название</td><td class="no-print aud">Аудитория</td> <td >Расположение</td> <td id="proverka"class="hidden-column"> Проверено</td> </tr>'
table.innerHTML += headTable
var tr =""
data.forEach(element => {
tr += '<tr onclick="tableclick(this)">'
tr += '<td>' + element.num_ved + '</td>'
tr += '<td clas="inv">' + element.inv_number + '</td>'
tr += '<td>' + element.oboruds_id + '</td>'
tr += '<td class="no-print">' + element.auditory_name + '</td>'
tr += '<td class="rasp">' +element.raspolog + '</td>'
tr += '<td>' + '\n' + '</td>'
tr += '</tr>'
});
table.innerHTML += tr
}
})
}

View File

@@ -1,32 +0,0 @@
$( document ).ready(function() {
$(".updatebtn").click(function(){
var audid = document.getElementById('auditory_dubl').value;
var invnum = document.getElementById('invnomer').textContent;
console.log('start perenos')
$.ajax({
url: "/perenos",
type: 'get',
contentType: 'application/json',
dataType: 'json',
data: {'audid':audid,
'invnum':invnum
},
error: function(error){
console.log(error);
}
})
invnomer.textContent=''
nazvanie.textContent=''
aud.textContent=''
auditory_dubl.selectedIndex = 0;
})
})

View File

View File

@@ -1,25 +0,0 @@
$("#printbutton").click(function(){
let aud = document.getElementById('auditory')
let audtext = aud.options[aud.selectedIndex].text;
const h2 = document.querySelector('h2');
h2.textContent = "Аудитория № " + audtext
document.getElementById("datatable").className="rs-table-bordered px-3"
let column = document.getElementById("proverka")
column.classList.remove("hidden-column")
window.print()
document.getElementById("datatable").className="table"
h2.textContent='распределение мат. ценностей'
column.classList.add("hidden-column")
})

View File

@@ -1,5 +0,0 @@
$("#printallbutton").click(function(){
console.log("aaaaaaa")
})

View File

@@ -1,125 +0,0 @@
function getData(){
const audid = document.getElementById('auditory')
$.ajax({
url: "/searchonaud",
type: "get",
contentType: 'application/json',
dataType: 'json',
data: {
auditory: audid.value
},
success: function(response){
var data = response;
const table = document.getElementById('datatable')
var headTable = '<tr> <td >Номер в Инв. вед</td> <td id="invnomer">Инв. номер</td><td>Название</td><td class="no-print aud">Аудитория</td> <td >Расположение</td> <td id="proverka"class="hidden-column"> Проверено</td> </tr>'
var tr =""
data.forEach(element => {
tr += '<tr onclick="tableclick(this)">'
tr += '<td>' + element.num_ved + '</td>'
tr += '<td clas="inv">' + element.inv_number + '</td>'
tr += '<td>' + element.oboruds_id + '</td>'
tr += '<td class="no-print">' + element.auditory_name + '</td>'
tr += '<td class="rasp">' +element.raspolog + '</td>'
tr += '<td>' + '\n' + '</td>'
tr += '</tr>'
});
table.innerHTML = headTable + tr
}
})
}
$("#searchbutton").click(function(){
getData();
})
$('#modalsavetodb').click(function(){
let rasp = document.getElementById('modal_rapolog')
let vedomost = document.getElementById('modal_vednumber')
let invnom = document.getElementById('modal_invnom')
let matcen = document.getElementById('modal_matcenn')
let changeddata = new Array()
changeddata[0] = invnom.text
changeddata[1] = vedomost.value
changeddata[2] = rasp.value
let sendData = changeddata.join(',')
changeddata = []
$.ajax({
url: "/addraspved",
type: "POST",
contentType: "application/json;charset=utf-8",
dataType: "json",
data: sendData,
success: function(){
/*
rasp='',
vedomost = '',
invnom = '',
matcen = '',
changeddata = []
*/
$('#getmodal').modal('hide').data( 'bs.modal', null );
getData();
}
})
})
function tableclick(tableRow){
let nomved = tableRow.childNodes[0].innerHTML;
let invnomer = tableRow.childNodes[1].innerHTML;
let nazvanie = tableRow.childNodes[2].innerHTML;
let raspolog = tableRow.childNodes[4].innerHTML;
$('#getmodal').modal('show')
let rasp = document.getElementById('modal_rapolog')
let vedomost = document.getElementById('modal_vednumber')
let invnom = document.getElementById('modal_invnom')
let matcen = document.getElementById('modal_matcenn')
invnom.innerText = invnomer
matcen.innerText = nazvanie.substring(0,15)
if (nomved.length >0){
vedomost.value = nomved
}
if(raspolog.length>0){
rasp.value = raspolog
}
$("#mimodal").on('hidden.bs.modal', function () {
$(this).data('bs.modal', null);
});
$('#modalclose').click(function(){
$('#getmodal').modal('hide').data( 'bs.modal', null );
} )
}

View File

@@ -1,47 +0,0 @@
function tableclick(x){
// let data = document.getElementById(x.rowIndex)
let datas = x.innerText.split('\t')
invnom.innerText=datas[1]+"\t"
matcen.innerText=datas[2]
if (datas[4].length>0){
rasp.value=datas[4];
}
if (datas[0].length>0){
vedomost.value=datas[0]
}
$('#modalclose').click(function(){
$('#getmodal').modal('hide');
} )
$('#modalsavetodb').click(function(){
$.ajax({
url: "/addraspved",
type: "POST",
contentType: "application/json;charset=utf-8",
dataType: "json",
data: {
rasp: rasp.value,
ved: vedomost.value,
inv: invnomer
},
success:function() {
rasp.value = '';
vedomost.value= '';
data=[];
rasp
$('#getmodal').modal('hide');
getData();
}
})
})}

View File

@@ -1,15 +0,0 @@
$( document ).ready(function() {
$(".reshbtn").click(function(){
var zmid = this.id
$.ajax({
url: "/zamrm",
type: 'get',
contentType: 'application/json',
dataType: 'json',
data: {'zmid':zmid},
})
var parent = document.getElementById('zambody')
var child = document.getElementById(zmid)
parent.removeChild(child)
})
})

View File

@@ -1,24 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<h5 class="card-title">Добавить аудиторию</h5>
<form method='POST' action="/addaudtodb" class="card" >
<input type="text" class="form-control" name="auditory">
<button> Добавить</button>
</form>
</div>
</div>
</div>
{%endblock%}

View File

@@ -1,147 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<!-- Modal -->
<div class="modal fade" id="getmodal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body" id="textarea">
<div class="row">
<a id="modal_invnom"> </a><a id="modal_matcenn"></a>
</div>
<div class="row">
№ из ведомости
<input type="text" class="form-control" id ='modal_vednumber' placeholder="Номер из ведомости">
</div>
<div class="row">
Количество
<input type="text" class="form-control" id ='modal_kolvo' placeholder="Количество">
</div>
<div class="row">
Балансовый счёт
<input type="text" class="form-control" id ='modal_balance' placeholder="Балансовый счёт">
</div>
<div class="row">
Расположение
<input type="text" class="form-control" id ='modal_rapolog' placeholder="Введите расположение">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" id="modalclose">Закрыть</button>
<button type="button" class="btn btn-primary" id="modalsavetodb" >Сохранить изменения</button>
</div>
</div>
</div>
</div>
</div>
<!-- Modal2 -->
<div class="modal fade" id="addmodal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body" id="textarea">
<div class="row">
<a id="modal_invnom"> </a><a id="modal2_matcenn"></a>
</div>
<div class="row">
№ из ведомости
<input type="text" class="form-control" id ='modal2_vednumber' placeholder="Номер из ведомости">
<div class="row">
Инвентарный номер
<input type="text" class="form-control" id ='modal2_invnom' placeholder="Инвентарный номер">
</div>
</div>
<div class="row">
Название
<input type="text" class="form-control" id ='modal2_nazvanie' placeholder="Название">
</div>
<div class="row">
Количество
<input type="text" class="form-control" id ='modal2_kolvo' placeholder="Количество">
</div>
<div class="row">
Балансовый счёт
<input type="text" class="form-control" id ='modal2_balance' placeholder="Балансовый счёт">
</div>
<div class="row">
Расположение
<input type="text" class="form-control" id ='modal2_rapolog' placeholder="Введите расположение">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" id="modal2close">Закрыть</button>
<button type="button" class="btn btn-primary" id="modal2savetodb" >Сохранить изменения</button>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<h3 id ='123' class=" no-print"> Все мат. ценности </h3>
</div>
<div class="row col-12">
<button class="button" id="printallbutton"> Печать </button>
</div>
<div class="row col-12">
<button class="button" id="addoborud"> Добавить </button>
</div>
<div class="row">
<div class="card col-md-11 table-responsive">
<table id="alldatatable" class="alldatable table pagebreak" >
<thead>
<tr>
<th scope="col"><br>п/п <br>АСУ</th>
<th scope="col">№ п/п <br>вед</th>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
<th scope="col">Кол-во</th>
<th scope="col">Счёт</th>
<th scope="col">Ауд - я</th>
<th scope="col">Расположение</th>
</tr>
</thead>
<tr>
</tr>
</table>
</div>
</div>
<script src="{{url_for('static', filename='js/allmatc.js') }}"></script>
{% endblock %}

View File

@@ -1,147 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<!-- Modal -->
<div class="modal fade" id="getmodal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body" id="textarea">
<div class="row">
<a id="modal_invnom"> </a><a id="modal_matcenn"></a>
</div>
<div class="row">
№ из ведомости
<input type="text" class="form-control" id ='modal_vednumber' placeholder="Номер из ведомости">
</div>
<div class="row">
Количество
<input type="text" class="form-control" id ='modal_kolvo' placeholder="Количество">
</div>
<div class="row">
Балансовый счёт
<input type="text" class="form-control" id ='modal_balance' placeholder="Балансовый счёт">
</div>
<div class="row">
Расположение
<input type="text" class="form-control" id ='modal_rapolog' placeholder="Введите расположение">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" id="modalclose">Закрыть</button>
<button type="button" class="btn btn-primary" id="modalsavetodb" >Сохранить изменения</button>
</div>
</div>
</div>
</div>
</div>
<!-- Modal2 -->
<div class="modal fade" id="addmodal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body" id="textarea">
<div class="row">
<a id="modal_invnom"> </a><a id="modal2_matcenn"></a>
</div>
<div class="row">
№ из ведомости
<input type="text" class="form-control" id ='modal2_vednumber' placeholder="Номер из ведомости">
<div class="row">
Инвентарный номер
<input type="text" class="form-control" id ='modal2_invnom' placeholder="Инвентарный номер">
</div>
</div>
<div class="row">
Название
<input type="text" class="form-control" id ='modal2_nazvanie' placeholder="Название">
</div>
<div class="row">
Количество
<input type="text" class="form-control" id ='modal2_kolvo' placeholder="Количество">
</div>
<div class="row">
Балансовый счёт
<input type="text" class="form-control" id ='modal2_balance' placeholder="Балансовый счёт">
</div>
<div class="row">
Расположение
<input type="text" class="form-control" id ='modal2_rapolog' placeholder="Введите расположение">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" id="modal2close">Закрыть</button>
<button type="button" class="btn btn-primary" id="modal2savetodb" >Сохранить изменения</button>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<h3 id ='123' class=" no-print"> Все мат. ценности </h3>
</div>
<div class="row col-12">
<button class="button" id="printallbutton"> Печать </button>
</div>
<div class="row col-12">
<button class="button" id="addoborud"> Добавить </button>
</div>
<div class="row">
<div class="card col-md-11 table-responsive">
<table id="alldatatable" class="alldatable table pagebreak" >
<thead>
<tr>
<th scope="col"><br>п/п <br>АСУ</th>
<th scope="col">№ п/п <br>вед</th>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
<th scope="col">Кол-во</th>
<th scope="col">Счёт</th>
<th scope="col">Ауд - я</th>
<th scope="col">Расположение</th>
</tr>
</thead>
<tr>
</tr>
</table>
</div>
</div>
<script src="{{url_for('static', filename='js/allmatc.js') }}"></script>
{% endblock %}

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css')}}">
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}">
<title class="no-print">Инвентаризация</title>
</head>
{% include 'head.html' %}
<div class="row no-print">
{% include 'navbar.html' %}
</div>
<body>
{% block content %} {% endblock %}
{% include 'js.html' %}
</body>
</html>

View File

@@ -1,13 +0,0 @@
<header >
<h1>
<a href="/">Инвентаризация кафедры <br>
"Автоматизированные системы управления"</br> </a>
</h1>
<h2>
распределение мат. ценностей
</h2>
</header>

View File

@@ -1,84 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="card col-md-6 col-10" >
<div class="card-body">
<form method="POST" action="/">
<input type="text" name="srch" placeholder="инвентарный номер">
<button> Найти </button>
</form>
</div>
</div>
</div>
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<h3 class="card-title"> Нераспределённые </h3>
<form method="POST" action="/addoborudtodb">
<table class="table" name="table" col-md-10>
<thead>
<tr>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
<th scope="col">Аудитория</th>
</tr>
{% for item in results: %}
<tr>
<td> <input type="hidden" name="invnomer" value="{{ item[0] }}"> {{ item[0] }} </td>
<td> {{ item[1] }} </td>
<td> <select name="auditory" id="auditory">
{% for item in aud: %}
<option name="optauditory" value="{{item.id}}">{{ item.audnazvanie }}</option>
{% endfor %}
</select>
</td>
</td>
</tr>
{% endfor %}
</table>
<button> Обновить</button>
</form>
</div>
</div>
</div>
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<h3 class="card-title"> Распределённые </h3>
<table class="table" col-md-10>
<thead>
<tr>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
<th scope="col">Аудитория исходная</th>
<th scope="col">Аудитория переноса</th>
</tr>
<td id="invnomer"> {{res1[0]}} </td>
<td id="nazvanie"> {{res1[1]}} </td>
<td id="aud"> {{res1[2]}} </td>
<td>
<select name="auditory" id="auditory_dubl">
{% for item in aud: %}
<option name="optauditory" value="{{item.id}}">{{ item.audnazvanie }}</option>
{% endfor %}
</select>
</td>
</table>
<button class="updatebtn" > Перенести </button>
</div>
</div>
</div>
{%endblock%}

View File

@@ -1,13 +0,0 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.js"></script>
<script src="{{url_for('static', filename='js/index.js') }}"></script>
<script src="{{url_for('static', filename='js/printall.js') }}"></script>
<script src="{{url_for('static', filename='js/zametki.js') }}"></script>
<script src="{{url_for('static', filename='js/searchonaud.js') }}"></script>
<script src="{{url_for('static', filename='js/print.js') }}"></script>
<script src="{{url_for('static', filename='js/modal.js') }}"></script>
<script src="{{url_for('static', filename='js/allmatc.js') }}"></script>

View File

@@ -1,62 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="card col-4" >
<div class="card-body">
<form class="form-horizontal">
<fieldset>
<!-- Form Name -->
<legend>Авторизация</legend>
<!-- Text input-->
<div class="form-group">
<label control-label" for="logininput">Логин</label>
<div>
<input id="logininput" name="logininput" type="text" placeholder="Введите логин" class="form-control input-md">
</div>
</div>
<!-- Password input-->
<div class="form-group">
<label class="control-label" for="passwordinput">Пароль</label>
<input id="passwordinput" name="passwordinput" type="password" placeholder="Введите пароль" class="form-control input-md">
</div>
</div>
<div class="row">
<button id="btn_login" name="btn_login" class="btn btn-primary">Войти</button>
</div>
</fieldset>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,39 +0,0 @@
<div class="row no-print">
<nav class="no-print navbar navbar-expand-lg navbar-light">
<div class="no-print container-fluid">
<button class="no-print navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="no-print navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="no-printnavbar-toggler-icon"></span>
</button>
<div class="no-print ollapse navbar-collapse" id="navbarSupportedContent">
<ul class="no-print navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item no-print">
<a class="nav-link no-print" aria-current="page" href="{{ url_for('index') }}">Главная</a>
</li>
<li class="nav-item no-print ">
<a class="nav-link no-print " aria-current="page" href="{{ url_for('alloborud') }}">Вся таблица</a>
</li>
<li class="nav-item no-print">
<a class="nav-link no-print" href="{{url_for('searchonaud')}}">Поаудиторно</a>
</li>
<li class="nav-item no-print">
<a class="nav-link no-print" aria-current="page" href="{{url_for('addAud')}}">Добавить аудиторию</a>
</li>
<li class="nav-item no-print">
<a class="nav-link no-print" aria-current="page" href="{{url_for('vneaud')}}">Не распределено</a>
</li>
<li class="nav-item no-print">
<a class="nav-link no-print" aria-current="page" href="{{url_for('zametki')}}">Заметки</a>
</li>
</ul>
</div>
</div>
</nav>
</div>

View File

@@ -1,49 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<form method="POST" action="/search">
<input type="text" name="srch" placeholder="инвентарный номер">
<button> Найти </button>
</form>
</div>
</div>
</div>
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<h3 class="card-title"> Распределённые </h3>
<form method="POST" action="/updateduplicate">
<table class="table" col-md-10>
<thead>
<tr>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
</tr>
</tr>
<td> {{res1[0]}} </td>
</table>
</form>
</div>
</div>
</div>
{%endblock%}

View File

@@ -1,59 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css')}}">
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}">
<title>Инвентаризация</title>
</head>
<body>
<header>
<h1>
Инвентаризация каф АСУ
</h1>
<h2>
Аудитория
</h2>
</header>
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<h3 class="card-title"> Поаудиторно </h3>
<form method="POST" action="/addoborudtodb">
<table class="table" id="datatable" col-md-10>
<thead>
<tr>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
<th scope="col">Аудитория</th>
</tr>
{% for item in res: %}
<tr>
<td> <input type="hidden" name="invnomer" value="{{ item[0] }}"> {{ item[0] }} </td>
<td> {{ item[1] }} </td>
<td>
{{item[2]}}
</td>
</td>
</tr>
{% endfor %}
</table>
</form>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,100 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<!-- Modal -->
<div class="modal fade" id="getmodal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body" id="textarea">
<input type="text" class="form-control" id='vednumber' placeholder="Номер из веломости">
<input type="text" class="form-control" id='rapolog' placeholder="Введите расположение">
<div class="row">
<a id="modal_invnom"> </a><a id="modal_matcenn"></a>
</div>
<form method="POST" action="/addraspved">
<div class="row">
№ из ведомости
<input type="text" class="form-control" name="modal_vednumber" id='modal_vednumber'
placeholder="Номер из ведомости">
</div>
<div class="row">
Расположение
<input type="text" class="form-control" name="modal_rapolog" id='modal_rapolog'
placeholder="Введите расположение">
</div>
</form>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" id="modalclose">Закрыть
</button>
<button type="button" class="btn btn-primary" id="modalsavetodb">Сохранить изменения</button>
</div>
</div>
</div>
</div>
</div>
<div class="row no-print">
<div class="card col-md-10 col-10">
<div class="card-body">
<select name="auditory" id="auditory">
{% for item in aud: %}
<option name="optauditory" value="{{ item.id }}">{{ item.audnazvanie }}</option>
{% endfor %}
</select>
<button id="searchbutton"> Найти</button>
<button id="printbutton"> Печать</button>
</div>
</div>
</div>
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<h3 class="card-title no-print"> Поаудиторно </h3>
<table class="table " id="datatable">
<th>Номер в Инв. вед</th>
<th>Инв. номер</th>
<th>Название</th>
<th class="no-print">Аудитория</th>
<th>Расположение</th>
{% for item in res %}
<td><input type="hidden" name="invnomer" value="{{ item[0] }}"> {{ item[0] }} </td>
<td> {{ item[1] }} </td>
<td class="no-print"> {{ item[2] }} </td>
<td id="proverka"> Проверено</td>
{% endfor %}
</table>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,34 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="card col-md-10 col-10">
<div class="card-body">
<form>
<h3 class="card-title"> Не распределено {{ kolvo }} штук из {{ all_kol }} </h3>
<table class="table" col-md-10>
<thead>
<tr>
<th scope="col">Инв. номер</th>
<th scope="col">Название</th>
</tr>
{% for item in res: %}
<tr>
<td> <input type="hidden" name="invnomer" value="{{ item[0] }}"> {{ item[0] }} </td>
<td> {{ item[1] }} </td>
<td> {{ item[2] }} </td>
<td> {{ item[3] }} </td>
</tr>
{% endfor %}
</table>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,39 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="card col-md-8 col-10">
<div class="card-body">
<h3 class="card-title"> Добавление заметки </h3>
<form method="POST" action="/zametki">
<textarea id="textzam" name="textzam" class="col-6"></textarea>
<div class="row">
<button> Добавить </button>
</div>
</form>
</div>
</div>
</div>
<div id="zambody" class="container col-12">
{% for item in zam: %}
<div class="row" id="{{ item.id }}">
<div class="card col-md-6 col-10">
<div class="card-body">
{{ item.txtzam }}
</div>
{{ item.created_date }}
<div class="row">
<button id="{{ item.id }}" class="reshbtn col-4"> Решено </button>
</div>
</div>
</div>
{% endfor %}
</div>
{%endblock%}