This commit is contained in:
Viktoria Polyakova
2025-03-29 17:13:06 +03:00
commit 409c60610a
11 changed files with 562 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
dist
build
.vscode
.venv
__pycache__

39
SignGenerator.spec Normal file
View File

@@ -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'],
)

1
build.sh Executable file
View File

@@ -0,0 +1 @@
python -m PyInstaller --onefile -n "SignGenerator" --windowed --icon=ui/sign.ico main.py

10
config.ini Normal file
View File

@@ -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

29
config.py Normal file
View File

@@ -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()

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

136
main.py Normal file
View File

@@ -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_())

9
requirements.txt Normal file
View File

@@ -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

11
template.html Normal file
View File

@@ -0,0 +1,11 @@
С уважением,<br>
{username}<br>
{jobtitle}<br>
<img src="{logo}" /><br>
Т.: {mgts}<br>
М.: {mobile}<br>
<a href="https://www.silart.com">www.silart.com</a><br>
<br>
Используем систему электронного документооборота (ЭДО).<br>
Система <b>Сбис</b>. Оператор <b>ЭДО</b> Компания ТЕНЗОР.<br>
Наш <b>ID 2BEc53781dc83984882a910c2486b6122a7</b>

322
ui/MainForm.ui Normal file
View File

@@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>ИП Полякова Виктория Валерьевна</author>
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>680</width>
<height>760</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true">Генератор подписи</string>
</property>
<widget class="QWidget" name="MainWidget">
<widget class="QPlainTextEdit" name="html_txt">
<property name="geometry">
<rect>
<x>20</x>
<y>530</y>
<width>641</width>
<height>171</height>
</rect>
</property>
</widget>
<widget class="QTextEdit" name="view_txt">
<property name="geometry">
<rect>
<x>20</x>
<y>260</y>
<width>641</width>
<height>261</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>100</horstretch>
<verstretch>100</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>23</y>
<width>641</width>
<height>232</height>
</rect>
</property>
<layout class="QVBoxLayout" name="ltInputData">
<item>
<layout class="QHBoxLayout" name="ltUserName">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="fname_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Имя:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fname_txt"/>
</item>
<item>
<widget class="QLabel" name="lname_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Фамилия:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lname_txt"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="ltJobTitle">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="jobtitle_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Должность:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="jobtitle_txt"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="ltMgts">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="mgts_lbl">
<property name="text">
<string notr="true">Рабочий телефон:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mgts_txt">
<property name="inputMask">
<string notr="true">+7 (000) 000-00-00;_</string>
</property>
<property name="text">
<string notr="true">+7 () --</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mgtsadd_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">добавочный:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mgtsadd_txt">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="inputMask">
<string notr="true">000;_</string>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="ltMobile">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="mobile_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Мобильный телефон:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mobile_txt">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="inputMask">
<string notr="true">+7 (000) 000-00-00;_</string>
</property>
<property name="text">
<string notr="true">+7 () --</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="ltTemplate">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="template_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Файл шаблона:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="template_txt"/>
</item>
<item>
<widget class="QPushButton" name="selecttemplate_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Выбрать</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="ltLogo">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="logo_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Файл логотипа:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="logo_txt"/>
</item>
<item>
<widget class="QPushButton" name="selectlogo_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Выбрать</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="generate_btn">
<property name="text">
<string notr="true">Просмотр</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="copy_btn">
<property name="geometry">
<rect>
<x>400</x>
<y>710</y>
<width>261</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Копировать в буфер обмена</string>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

BIN
ui/sign.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB