From 409c60610a42bd51d8f7e53ba483918a2fe7dd5e Mon Sep 17 00:00:00 2001 From: Viktoria Polyakova Date: Sat, 29 Mar 2025 17:13:06 +0300 Subject: [PATCH] Init --- .gitignore | 5 + SignGenerator.spec | 39 ++++++ build.sh | 1 + config.ini | 10 ++ config.py | 29 ++++ logo.png | Bin 0 -> 3105 bytes main.py | 136 +++++++++++++++++++ requirements.txt | 9 ++ template.html | 11 ++ ui/MainForm.ui | 322 +++++++++++++++++++++++++++++++++++++++++++++ ui/sign.ico | Bin 0 -> 67646 bytes 11 files changed, 562 insertions(+) create mode 100644 .gitignore create mode 100644 SignGenerator.spec create mode 100755 build.sh create mode 100644 config.ini create mode 100644 config.py create mode 100644 logo.png create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 template.html create mode 100644 ui/MainForm.ui create mode 100644 ui/sign.ico diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f275eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +dist +build +.vscode +.venv +__pycache__ diff --git a/SignGenerator.spec b/SignGenerator.spec new file mode 100644 index 0000000..9e16978 --- /dev/null +++ b/SignGenerator.spec @@ -0,0 +1,39 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['main.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='SignGenerator', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon=['ui/sign.ico'], +) diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..e2173b6 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +python -m PyInstaller --onefile -n "SignGenerator" --windowed --icon=ui/sign.ico main.py \ No newline at end of file diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..1e6d8c9 --- /dev/null +++ b/config.ini @@ -0,0 +1,10 @@ +[General] +firstname = Сергей +lastname = Гусенков +jobtitle = Руководитель отдела продаж +gtsphone = +7 (499) 229-60-00 +gtsphoneadd = 303 +mobilephone = +7 (993) 666-52-51 +logo = logo.png +template = template.html + diff --git a/config.py b/config.py new file mode 100644 index 0000000..91ed493 --- /dev/null +++ b/config.py @@ -0,0 +1,29 @@ +from configparser import ConfigParser +from os.path import exists + +cfg = ConfigParser() +cfg['General'] = {} +cfg['General']['FirstName'] = '' +cfg['General']['LastName'] = '' +cfg['General']['JobTitle'] = '' +cfg['General']['GTSPhone'] = '' +cfg['General']['GTSPhoneAdd'] = '' +cfg['General']['MobilePhone'] = '' +cfg['General']['Logo'] = 'logo.png' +cfg['General']['Template'] = 'template.html' + + +def save_config(cfg): + with open('config.ini', 'w', encoding='utf-8') as configfile: + cfg.write(configfile) + + +def load_config(): + if not exists('config.ini'): + with open('config.ini', 'w', encoding='utf-8') as configfile: + cfg.write(configfile) + else: + cfg.read('config.ini', encoding='utf-8') + +load_config() + diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e5ed3ccccdb4f456ac79e870ecbf2f7ecbff5ecc GIT binary patch literal 3105 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 literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 0000000..4856438 --- /dev/null +++ b/main.py @@ -0,0 +1,136 @@ +import sys +from PyQt5 import uic +from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QMessageBox, QFileDialog +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon +from config import * +from base64 import b64encode +from os.path import exists + + +class MainForm(QMainWindow): + def __init__(self, cfg): + super().__init__() + uic.loadUi('ui/MainForm.ui', self) + self.setWindowIcon(QIcon('ui/sign.ico')) + + self.cfg = cfg + self.fname_txt.setText(cfg['General']['firstname']) + self.lname_txt.setText(cfg['General']['lastname']) + self.jobtitle_txt.setText(cfg['General']['jobtitle']) + self.mgts_txt.setText(cfg['General']['gtsphone']) + self.mgtsadd_txt.setText(cfg['General']['gtsphoneadd']) + self.mobile_txt.setText(cfg['General']['mobilephone']) + self.template_txt.setText(cfg['General']['template']) + self.logo_txt.setText(cfg['General']['logo']) + + self.selecttemplate_btn.clicked.connect(self.selecttemplate_btn_clicked) + self.selectlogo_btn.clicked.connect(self.selectlogo_btn_clicked) + self.generate_btn.clicked.connect(self.generate_btn_clicked) + self.copy_btn.clicked.connect(self.copy_btn_clicked) + + + def selecttemplate_btn_clicked(self): + tmpl = QFileDialog.getOpenFileName(self, 'Выбрать файл шаблона', '', filter='Шаблон HTML (*.html)')[0] + if tmpl: + self.template_txt.setText(tmpl) + self.template_txt.setFocus() + + + def selectlogo_btn_clicked(self): + logo = QFileDialog.getOpenFileName(self, 'Выбрать файл логотипа', '', filter='Логотип PNG (*.png)')[0] + if logo: + self.logo_txt.setText(logo) + self.logo_txt.setFocus() + + + def generate_btn_clicked(self): + fname = self.fname_txt.text() + lname = self.lname_txt.text() + jobtitle = self.jobtitle_txt.text() + if self.mgts_txt.text() == '+7 () --': + mgts = '' + else: + mgts = self.mgts_txt.text() + mgtsadd = self.mgtsadd_txt.text() + if self.mobile_txt.text() == '+7 () --': + mobile = '' + else: + mobile = self.mobile_txt.text() + template = self.template_txt.text() + logo = self.logo_txt.text() + + username = fname + ' ' + lname + + if not exists(template): + alrt = QMessageBox(self) + alrt.setWindowIcon(self.windowIcon()) + alrt.setWindowTitle('Ошибка') + alrt.setText('Не найден шаблон!') + alrt.setStandardButtons(QMessageBox.Ok) + alrt.setIcon(QMessageBox.Warning) + alrt.exec_() + return + + with open(template, 'r', encoding='utf-8') as f: + text = f.read() + + if not exists(logo): + alrt = QMessageBox(self) + alrt.setWindowIcon(self.windowIcon()) + alrt.setWindowTitle('Ошибка') + alrt.setText('Не найден логотип!') + alrt.setStandardButtons(QMessageBox.Ok) + alrt.setIcon(QMessageBox.Warning) + alrt.exec_() + return + + with open(logo, 'rb') as f: + logo_b64 = 'data:image/png;base64, ' + str(b64encode(f.read()))[2:-1] + + workphone = mgts + if mgtsadd: + workphone += ' доб. ' + mgtsadd + + text = text.format(username=username, logo=logo_b64, jobtitle=jobtitle, mgts=workphone, mobile=mobile) + self.view_txt.setHtml(text) + self.html_txt.setPlainText(text) + + cfg['General']['firstname'] = fname + cfg['General']['lastname'] = lname + cfg['General']['jobtitle'] = jobtitle + cfg['General']['gtsphone'] = mgts + cfg['General']['gtsphoneadd'] = mgtsadd + cfg['General']['mobilephone'] = mobile + cfg['General']['template'] = template + cfg['General']['logo'] = logo + + save_config(cfg) + + def copy_btn_clicked(self): + self.html_txt.selectAll() + self.html_txt.copy() + alrt = QMessageBox(self) + alrt.setWindowIcon(self.windowIcon()) + alrt.setWindowTitle('Сообщение') + alrt.setText('Текст скопирован!') + alrt.setStandardButtons(QMessageBox.Ok) + alrt.setIcon(QMessageBox.Information) + alrt.exec_() + + + def center(self): + qr = self.frameGeometry() + cp = QDesktopWidget().availableGeometry().center() + qr.moveCenter(cp) + self.move(qr.topLeft()) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = MainForm(cfg) + ex.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint) + ex.setFixedSize(680, 760) + ex.center() + ex.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4b5a780 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +altgraph==0.17.4 +configparser==7.2.0 +packaging==24.2 +pyinstaller==6.12.0 +pyinstaller-hooks-contrib==2025.2 +PyQt5==5.15.11 +PyQt5-Qt5==5.15.16 +PyQt5_sip==12.17.0 +setuptools==78.1.0 diff --git a/template.html b/template.html new file mode 100644 index 0000000..9a29858 --- /dev/null +++ b/template.html @@ -0,0 +1,11 @@ +С уважением,
+{username}
+{jobtitle}
+
+Т.: {mgts}
+М.: {mobile}
+www.silart.com
+
+Используем систему электронного документооборота (ЭДО).
+Система Сбис. Оператор ЭДО Компания ТЕНЗОР.
+Наш ID 2BEc53781dc83984882a910c2486b6122a7 \ No newline at end of file diff --git a/ui/MainForm.ui b/ui/MainForm.ui new file mode 100644 index 0000000..d42e250 --- /dev/null +++ b/ui/MainForm.ui @@ -0,0 +1,322 @@ + + + ИП Полякова Виктория Валерьевна + MainWindow + + + + 0 + 0 + 680 + 760 + + + + + 0 + 0 + + + + Генератор подписи + + + + + + 20 + 530 + 641 + 171 + + + + + + + 20 + 260 + 641 + 261 + + + + + 100 + 100 + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> +p, li { white-space: pre-wrap; } +hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } +</style></head><body style=" font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + 20 + 23 + 641 + 232 + + + + + + + 10 + + + + + + 0 + 0 + + + + Имя: + + + + + + + + + + + 0 + 0 + + + + Фамилия: + + + + + + + + + + + + 10 + + + + + + 0 + 0 + + + + Должность: + + + + + + + + + + + + 10 + + + + + Рабочий телефон: + + + + + + + +7 (000) 000-00-00;_ + + + +7 () -- + + + + + + + + 0 + 0 + + + + добавочный: + + + + + + + + 0 + 0 + + + + 000;_ + + + + + + + + + + + + 10 + + + + + + 0 + 0 + + + + Мобильный телефон: + + + + + + + + 0 + 0 + + + + +7 (000) 000-00-00;_ + + + +7 () -- + + + + + + + + + 10 + + + + + + 0 + 0 + + + + Файл шаблона: + + + + + + + + + + + 0 + 0 + + + + Выбрать + + + + + + + + + 10 + + + + + + 0 + 0 + + + + Файл логотипа: + + + + + + + + + + + 0 + 0 + + + + Выбрать + + + + + + + + + Просмотр + + + + + + + + + 400 + 710 + 261 + 31 + + + + Копировать в буфер обмена + + + + + + + diff --git a/ui/sign.ico b/ui/sign.ico new file mode 100644 index 0000000000000000000000000000000000000000..7035e4cc91e61cbf8dc08972c9fc1b64aafaee95 GIT binary patch literal 67646 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 T^keKk`5)svyDRd~e-HdGy8lZQ literal 0 HcmV?d00001