Ejemplo n.º 1
0
    def __init__(self, sql_main, PKValue, edit_mode, flags=Qt.WindowFlags()):
        super().__init__(Ui_Form_Edit(),
                         sql_main=sql_main,
                         PKValue=PKValue,
                         edit_mode=edit_mode,
                         flags=flags)

        MF = JPPub().MainForm
        MF.addLogoToLabel(self.ui.label_logo)
        MF.addOneButtonIcon(self.ui.butSave, 'save.png')
        MF.addOneButtonIcon(self.ui.butCancel, 'cancel.png')
        self.readData()
        self.ui.fUserID.setEnabled(False)
        self.ui.fPassword.setEnabled(True)
        self.ui.fPassword.refreshValueNotRaiseEvent("1234", True)
        self.ui.fPassword.passWordConver = md5_passwd
Ejemplo n.º 2
0
class EditForm_Archive(JPFormModelMain):
    currentRowEditComplete = pyqtSignal(int)

    def __init__(self, sql_main, PKValue, edit_mode, flags=Qt.WindowFlags()):
        super().__init__(Ui_Form_Edit(),
                         sql_main=sql_main,
                         PKValue=PKValue,
                         edit_mode=edit_mode,
                         flags=flags)
        self.MainForm = JPPub().MainForm
        self.MainForm.addLogoToLabel(self.ui.label_logo)
        self.MainForm.addOneButtonIcon(self.ui.butSave, 'save.png')
        self.MainForm.addOneButtonIcon(self.ui.butCancel, 'cancel.png')

        # 设置listWidget的格式
        cfg = ConfigInfo()
        temp = [int(r) for r in cfg.viewpdf.pagesize.split(',')]
        self.pdfPageSize = QSize(temp[0], temp[1])
        self.icoSize = QSize(96, 96)
        self.ui.listWidget.setSpacing(5)
        self.ui.listWidget.setGridSize(self.pdfPageSize)
        self.ui.listWidget.setResizeMode(QListWidget.Adjust)
        self.ui.listWidget.setIconSize(self.pdfPageSize)
        self.ui.listWidget.setViewMode(QListWidget.IconMode)
        self.ui.listWidget.itemDoubleClicked.connect(
            self.listItemDoubleClicked)
        # 保存最后一次点击的信息,时间和节点,防止重复点击
        self.laseDoubleInfo = []
        self.ui.listWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.ui.listWidget.customContextMenuRequested[QPoint].connect(
            self.rightClicked)
        # 标签文本自动换行
        self.ui.listWidget.setFlow(QListView.LeftToRight)
        self.ui.listWidget.setWrapping(True)
        self.ui.label_ProjectLink.setWordWrap(True)
        self._currentEditModelRow = None
        self.ui.fUserID.hide()
        # 附件有无修改的标志
        self.addtionalChanged = False
        self.pop: FormPopProgressBar = None
        # 存放用户已经选择的关联项目
        self.projectKeyList = []
        self.projectKeyListChanged = False

        editStyle = """border: 1px groove gray;
                        border-radius: 3px;
                        padding: 2px 4px;
                        border-width: 1px;
                        border-style: solid;
                        background-color: white;
                        border-color: rgb(171, 171, 171);"""
        readStyle = """border: 1px groove gray;
                        border-radius: 3px;
                        padding: 2px 4px;
                        border-width: 1px;
                        border-style: solid;
                        border-color: rgb(171, 171, 171);"""
        if self.isNewMode or self.isEditMode:
            self.ui.label_ProjectLink.setStyleSheet(editStyle)
            self.ui.label_ProjectLink.mouseDoubleClickEvent = self.on_but_SelectProject_clicked
        else:
            self.ui.label_ProjectLink.setStyleSheet(readStyle)
            self.ui.listWidget.setStyleSheet(
                "background-color: rgb(239, 239, 239);")
        # addtionalInfo用来以文件为行,保存档案的附件数据,用于保存命令等
        self.addtionalInfo = []
        # listIcos是一个列表,内部存放所有在listWidget中显示的图标
        #self.listIcos = []
        # 下面的链表,用于存放listIcos中可用于放大显示的图片
        self.viewPicInfos = BilateralLinkList()
        # # 一个只包含PDF页面和图片的列表,由编辑窗体维护,用于放大显示时用
        # self.ViewPdfAndPic = []

        #
        self.archivesPathInDatabase = os.path.abspath(
            JPPub().getConfigData()["archives_path"])
        if self.isNewMode:
            self.ui.fUserID.setText(str(JPUser().currentUserID()))
        self.readData()
        if (not self.isNewMode) and self.ui.archives_pk.text():
            sql = "select project_pk from "
            sql = sql + "t_archives_project where archives_pk={}"
            dic = JPDb().getDict(
                sql.format(self.ui.archives_pk.text().replace(",", "")))
            projects = [str(r['project_pk']) for r in dic]
            if projects:
                self.readProject(projects)

        self.ui.archives_pk.setEnabled(False)
        self.ui.issuing_date.setFocus()
        QGuiApplication.processEvents()
        # QGuiApplication.processEvents()
        # self.repaint()
        self.readAddtionalFromDatabase()
        self.initAdditional(self.addtionalInfo)

        # 根据窗体编辑状态设置窗体中按钮的显示状态
        if self.isReadOnlyMode:
            self.ui.but_SelectProject.setEnabled(False)
            # self.ui.btn_Download.setEnabled(False)
            self.ui.btn_Add.setEnabled(False)
            self.ui.btn_Delete.setEnabled(False)

    def closeEvent(self, event):
        self.ui.listWidget.clear()
        import gc
        del self.addtionalInfo
        del self.projectKeyList
        del self.viewPicInfos
        gc.collect()
        event.accept()

    def initAdditional(self, dic):
        def dispOK():
            if self.pop:
                self.pop.close()
                self.pop = None

        if dic:
            self.pop = FormPopProgressBar(self)
            self.xc = MyThreadReadAddition(dic)
            self.xc.onePixmCreated.connect(self.addOnePixmaptoForm)
            self.xc.oneFileLoaded.connect(self.pop.dispInfoStep)
            self.xc.finished.connect(dispOK)
            self.pop.open()
            self.pop.dispInfo("正在准备加载附件信息")
            self.pop.setMaximum(len(dic))
            self.xc.start()

    def listWidgetRightMenuSlot(self, point, act):
        actname = act.text()[0:2]
        if actname == '删除':
            item = self.ui.listWidget.itemAt(point)
            md5FileName = item.picInfo.md5FileName
            # 从连表中删除
            self.viewPicInfos.remove(item.picInfo)
            # 从附件列表中删除
            lst = [
                r for r in self.addtionalInfo if r.md5FileName == md5FileName
            ]
            if lst:
                lst[0].deleted = True
            # 从listWidget中删除条目,先要用takeItem取出才能成功
            for index in reversed(range(self.ui.listWidget.count())):
                t = self.ui.listWidget.item(index)
                if t.picInfo.md5FileName == md5FileName:
                    self.ui.listWidget.takeItem(index)
                    del t
            self.ui.listWidget.removeItemWidget(item)
            self.addtionalChanged = True
            # self.ui.listWidget.repaint()
        if actname == '添加':
            self.on_btn_Add_clicked()
        if actname == '下载':
            item = self.ui.listWidget.itemAt(point)
            md5FileName = item.picInfo.md5FileName
            lst = [
                r for r in self.addtionalInfo if (r.md5FileName == md5FileName)
            ]
            self.on_btn_Download_clicked(lst)

    def rightClicked(self, point):
        item = self.ui.listWidget.itemAt(point)
        fn = ''
        if item:
            fn = item.picInfo.originalName
        popMenu = QMenu()
        if self.isEditMode or self.isNewMode:
            popMenu.addAction(QAction(
                u'添加',
                self,
            ))
        if (self.isEditMode or self.isNewMode) and item:
            popMenu.addAction(QAction(u'删除 [{}]'.format(fn), self))
        if item:
            popMenu.addAction(QAction(u'下载 [{}]'.format(fn), self))
        popMenu.triggered.connect(partial(self.listWidgetRightMenuSlot, point))
        popMenu.exec_(QCursor.pos())

    def listItemDoubleClicked(self, item):
        def check(item):
            cunzai = [r for r in self.laseDoubleInfo if r.item is item]
            if not cunzai:
                t = datetime.datetime.now()
                self.laseDoubleInfo.append(lastDoubleItemInfo(item, t))
                return True
            else:
                n = datetime.datetime.now()
                if (n - cunzai[0].clickTime).seconds > 3:
                    cunzai[0].clickTime = n
                    return True
                else:
                    t = "您刚刚点击过本条目,正在调用系统功能打开文件,请不要重复点击!"
                    QMessageBox.warning(self, '提示', t, QMessageBox.ok)

        if item.picInfo.iconPath:
            if not check(item):
                return
            self.pop = FormPopProgressBar(self)
            self.pop.setMinimumDuration(0)
            self.pop.open()
            self.pop.reset(2)
            uid = JPUser().currentUserID()
            tm = time.strftime('%Y%m%d%H%M%S', time.localtime())
            topath = os.path.join(os.getcwd(), "temp", "{}_{}".format(uid, tm))
            if not os.path.exists(topath):
                os.makedirs(topath)
            topath = os.path.join(topath,
                                  item.picInfo.originalName.replace(" ", ''))
            self.pop.dispInfo("正在下载{}".format(item.picInfo.originalName), 1)
            myCopy(item.picInfo.originalPath, topath)
            self.pop.dispDelayed(
                "正在调用系统功能打开文件{},请稍候....".format(item.picInfo.originalName), 2)
            os.system(topath)

        else:
            frm = Form_ViewPic(self, item.picInfo, self.viewPicInfos)
            # frm.setData(item.picInfo, self.viewPicInfos)
            frm.show

    def addOnePixmaptoForm(self, item: picInfo):
        QPixmapCache.clear()
        if 'pixcount' not in self.__dict__:
            self.pixcount = 1
        else:
            self.pixcount += 1
        logging.getLogger().debug("得到一个图片信息准备加载:{}".format(self.pixcount))
        obj = None
        pItem = None
        if item.viewPixmap:
            obj = item.viewPixmap
            self.viewPicInfos.append(item)
            pItem = QListWidgetItem(
                QIcon(
                    obj.scaled(self.icoSize, Qt.KeepAspectRatio,
                               Qt.SmoothTransformation)), '')
        elif item.viewPixmap_Ico:
            obj = item.viewPixmap_Ico
            pItem = QListWidgetItem(
                QIcon(
                    obj.scaled(self.icoSize, Qt.KeepAspectRatio,
                               Qt.SmoothTransformation)), '')

        pItem.setSizeHint(self.pdfPageSize)
        pItem.picInfo = item
        pItem.setToolTip(item.originalName)
        pItem.setText(item.icoText if item.icoText else item.originalName)
        self.ui.listWidget.addItem(pItem)
        QGuiApplication.processEvents()

    def onGetFieldsRowSources(self):
        pub = JPPub()
        return [('archive_type', pub.getEnumList(5), 1)]

    def readProject(self, pklst):
        self.projectKeyList = pklst
        if pklst:
            sql = """
                SELECT group_concat(project_pk) as pks,
                    group_concat(project_simple_name) as nms
                FROM t_project_base_info
                WHERE project_pk IN ({})
                """
            sql = sql.format(',\n'.join(pklst))
            data = JPDb().getDataList(sql)
            self.ui.label_ProjectLink.setText(data[0][1])
        else:
            self.ui.label_ProjectLink.setText("")
        return

    def readAddtionalFromDatabase(self):
        """从数据库中加载给定PK的一个文档的所有附件信息到一个列表中"""
        sql = """
        select additional_pk,
            archives_pk,
            file_index,
            file_type,
            file_pk,
            original_name,
            '' as original_path,
            file_name,
            False as deleted
        from v_additional_archives
        where archives_pk={}
        order by file_index
        """
        if not self.isNewMode:
            # 从数据库取数据,生成多个addtionalInfo对象
            pk = self.ui.archives_pk.text().replace(",", "")
            d_path = self.archivesPathInDatabase
            dic = JPDb().getDict(sql.format(pk))
            for r in dic:
                add = addtionalInfo()
                for k in add.__dict__.keys():
                    if k in r:
                        add.__dict__[k] = r[k]
                add.md5FilePath = os.path.join(d_path, r['file_name'])
                add.md5FileName = os.path.splitext(r['file_name'])[0]
                add.isNew = False
                self.addtionalInfo.append(add)

    def onFirstHasDirty(self):
        self.ui.butSave.setEnabled(True)

    @pyqtSlot()
    def on_butCancel_clicked(self):
        self.close()

    @pyqtSlot()
    # 已经调试 增加一个附件
    def on_btn_Add_clicked(self):
        def getExName(filepath):
            return os.path.splitext(filepath)[1][1:]

        def md5Exist(filepath: str) -> dict:
            """检查文件是否在数据库中已经存在"""
            sql = """select file_pk, file_type,concat('{md5}','.',file_type)  md5FileShortName
            from t_additionals as f where filemd5=unhex('{md5}') limit 1;"""
            md5FileName = GetFileMd5(filepath)
            dic = JPDb().getDict(sql.format(md5=md5FileName))
            dPath = self.archivesPathInDatabase
            if dic:
                r0 = dic[0]
                r0['md5FilePath'] = os.path.join(dPath, r0['md5FileShortName'])
                r0['md5FileName'] = md5FileName
                return r0
            else:
                r0 = {'md5FileName': md5FileName}
                r0['md5FilePath'] = os.path.join(
                    dPath, md5FileName + "." + getExName(filepath))
                return r0

        fileName_choose, filetype = QFileDialog.getOpenFileNames(
            self,
            "Select a File",
            JPPub().getOrSetlastOpenDir(),  # 起始路径
            "Files (*.jpg *.PDF *.doc *.docx *.xls *.xlsx)")
        if fileName_choose:
            JPPub().getOrSetlastOpenDir(fileName_choose[0])
        curList = []
        self.pop = FormPopProgressBar(self)
        self.pop.open()
        self.pop.reset(len(fileName_choose))
        des = self.ui.archive_describe
        for i, original_path in enumerate(fileName_choose):
            if not re.search('包含文件:', des.toPlainText()):
                des.append('包含文件:\n{}'.format('-' * 150))
            self.ui.archive_describe.append(os.path.basename(original_path))
            self.pop.dispInfo(original_path, i + 1)
            dicrow = addtionalInfo()
            # 检查文件是不是刚刚在窗体中增加过一次
            upLoadFile = [
                r.original_path for r in self.addtionalInfo
                if not r.archives_pk
            ]
            if original_path in upLoadFile:
                self.ui.Label_Info.setText(
                    "文件【{}】刚刚已经增加".format(original_path))
                continue
            # 检查要上传的文件在数据库中是不是已经存在
            #exist, md5FileName, md5BaseName, lst = md5Exist(original_path)
            dic_temp = md5Exist(original_path)
            if 'file_pk' in dic_temp.keys():
                dicrow.file_pk = dic_temp['file_pk']
                dicrow.file_type = dic_temp['file_type']
                dispTxt = "【{}】文件在数据库中存在,已经用数据库中文件替代显示!"
                self.ui.Label_Info.setText(
                    dispTxt.format(os.path.basename(original_path)))
            else:
                dicrow.file_type = getExName(original_path)
            dicrow.md5FileName = dic_temp['md5FileName']
            dicrow.md5FilePath = dic_temp['md5FilePath']
            dicrow.original_path = os.path.abspath(original_path)
            dicrow.original_name = os.path.basename(original_path)
            dicrow.file_index = len(self.addtionalInfo)
            self.addtionalInfo.append(dicrow)
            curList.append(dicrow)

            # print(dicrow)
        if curList:
            self.initAdditional(curList)
            self.firstHasDirty.emit()
            self.addtionalChanged = True
        if self.pop:
            self.pop.close()
            self.pop = None

    @pyqtSlot()
    # 已经调试
    def on_but_SelectProject_clicked(self, *args):
        # self.
        # rows = self.ui.tableWidget_Project.rowCount()
        # sels = [self.ui.tableWidget_Project.item(
        #     i, 0).text() for i in range(rows)]
        frm = FormSelectProject(self.projectKeyList)
        frm.selectItemChanged.connect(self.readProject)
        frm.show()
        self.firstHasDirty.emit()
        self.projectKeyListChanged = True

    @pyqtSlot()
    # 已经调试
    def on_btn_Download_clicked(self, addtionalInfoRow=None):
        # 生成临时文件夹
        tm = time.strftime('%Y%m%d%H%M%S', time.localtime())
        uid = JPUser().currentUserID()
        topath = os.path.join(os.getcwd(), "temp", "{}_{}".format(uid, tm))
        if not os.path.exists(topath):
            os.makedirs(topath)
        # 下载文件列表
        lst = addtionalInfoRow if addtionalInfoRow else \
            [item for item in self.addtionalInfo if not item.deleted]
        copylst = []
        for i, item in enumerate(lst):
            if item.archives_pk:
                fr = os.path.join(self.archivesPathInDatabase,
                                  item.md5FilePath)
                to = os.path.join(topath, item.original_name)
                copylst.append([fr, to])
            else:
                fr = item.original_path
                to = os.path.join(topath, item.original_name)
                copylst.append([fr, to])
        pop = FormPopProgressBar(self)
        pop.reset(len(copylst) - 1)
        for r in copylst:
            pop.dispInfo("复制{}".format(r[1]), i)
            myCopy(r[0], r[1])
        pop.close()
        txt = '文件保存在:【{}】,点击确定打开该文件夹!'.format(topath)
        if QMessageBox.question(self, '完成', txt,
                                (QMessageBox.Yes | QMessageBox.No),
                                QMessageBox.Yes) == QMessageBox.Yes:
            topath1 = os.path.abspath(topath)
            os.system("start explorer {}".format(topath1))

    @pyqtSlot()
    def on_butSave_clicked(self):
        try:
            s1 = self.getSqls(self.PKRole)
        except Exception as e:
            t = '生成保存档案数据SQL命令出错,错误信息:\n{}'
            msgBox = QMessageBox(QMessageBox.Critical, u'提示', t.format(str(e)))
            msgBox.exec_()
            return

        try:
            s2 = self.CopyPicAndGetSaveFileSQL()
        except Exception as e:
            t = '复制文件或生成保存文件数据SQL命令出错,错误信息:\n{}'
            msgBox = QMessageBox(QMessageBox.Critical, u'提示', t.format(str(e)))
            msgBox.exec_()
            return
        pkSQL = []
        if self.isNewMode:
            sPK = JPDb().LAST_INSERT_ID_SQL()
            pkSQL.append("{} into @archives_pk;".format(sPK))
        if self.isEditMode:
            cur_pk = self.ui.archives_pk.text().replace(",", "")
            pkSQL.append('Select {} into @archives_pk;'.format(cur_pk))
        # 更新关联项目的SQL
        up_projectSQL = self.getUpdateProjectSQL()
        # 拼接所有SQL
        SQLS = s1[0:len(s1) - 1] + pkSQL + up_projectSQL + s2
        SQLS.append("Select @archives_pk;")

        # 执行sql
        try:
            print(SQLS)
            isOK, result = JPDb().executeTransaction(SQLS)
            if isOK:
                self.ui.butSave.setEnabled(False)
                self.afterSaveData.emit(result)
                self.currentRowEditComplete.emit(self._currentEditModelRow)
                QMessageBox.information(self, '完成',
                                        '保存数据完成!\nSave data complete!')
        except Exception as e:
            msgBox = QMessageBox(QMessageBox.Critical, u'提示', str(e))
            msgBox.exec_()
        finally:
            self.close()

    def getUpdateProjectSQL(self):
        result = []
        if not self.projectKeyListChanged:
            return result
        if self.isEditMode:
            delSQL = """delete from t_archives_project
                        where archives_pk=@archives_pk;"""
            result.append(delSQL)
        for pk in self.projectKeyList:
            temp_sql = """INSERT INTO t_archives_project
                        (archives_pk, project_pk)
                        VALUES (@archives_pk,{});"""
            result.append(temp_sql.format(pk))
        return result

    # 附件保存按钮
    def CopyPicAndGetSaveFileSQL(self) -> list:
        sqls = []
        if not self.addtionalChanged:
            return sqls
        used_sql = """
                select archives_pk from t_additionals_archives
                where file_pk={file_pk}
                    and archives_pk<>{archives_pk} limit 1;
                """
        del_sql = """
                delete from t_additionals_archives
                where archives_pk={archives_pk}
                    and file_pk={file_pk};
                """
        ins_file = """
                insert into t_additionals
                    (original_name,filemd5,file_type)
                    Values ('{original_name}',
                    unhex('{filemd5}'),'{file_type}');
                """
        ins_add = """
                insert into t_additionals_archives
                    (archives_pk,file_pk,file_index)
                    Values ({archives_pk},{file_pk},{file_index});
                """
        up_index = """update t_additionals_archives
                        set file_index={file_index}
                        where archives_pk={archives_pk}
                            and file_pk={file_pk}"""
        temp_id = self.ui.archives_pk.text()
        cur_pk = temp_id.replace(",", "") if self.isEditMode else ''
        if self.isNewMode:

            cur_pk = '@archives_pk'

        def fileIsUsed(file_pk, archives_pk):
            s = used_sql.format(file_pk=file_pk, archives_pk=archives_pk)
            return JPDb().executeTransaction(s)

        # self.setCursor(Qt.WaitCursor)
        for iRow, r in enumerate(self.addtionalInfo):
            # 删除情况1:用户删除了一个数据库已经存在的文件
            if r.archives_pk and r.deleted:
                # 删除本附件对文件的引用
                tempsql = del_sql.format(file_pk=r.file_pk,
                                         archives_pk=r.archives_pk)
                sqls.append(tempsql)
                if fileIsUsed(r.file_pk, r.archives_pk):
                    # 如果文件已经被其他附件引用,则只删除本附件的引用
                    continue
                else:
                    # 如果没有没有被其他用户引用,物理删除之
                    filePath = r.md5FilePath
                    if os.path.exists(filePath):
                        self.ui.Label_Info.setText("正在删除【{}】".format(filePath))
                        os.remove(filePath)
                        self.self.ui.Label_Info.setText('')
            # 删除情况2:如果是刚刚增加的文件被用户删除,则跳过不处理本行数据
            if not r.archives_pk and r.deleted:
                continue

            # 增加情况1:增加的文件数据库中已经有其他附件引用
            # if r.file_pk and not r.deleted:
            if r.isNew and r.file_pk:
                p_s = ins_add.format(archives_pk=cur_pk,
                                     file_pk=r.file_pk,
                                     file_index=iRow)
                sqls.append(p_s)
            # 增加情况2:增加的文件数据库中不存在,进行物理复制
            # if not r.file_pk and not r.archives_pk:
            if r.isNew and not r.file_pk:
                p_s = "{con_path}/{filemd5}.{file_type}"
                # newPath = p_s.format(
                #     con_path=self.archivesPathInDatabase,
                #     filemd5=r.md5FileName,
                #     file_type=r.file_type)
                self.ui.Label_Info.setText("正在复制【{}】".format(r.original_path))
                myCopy(r.original_path, r.md5FilePath)
                self.ui.Label_Info.setText('')
                # 先增加一个文件,后面要用到自动生成的文件PK
                tempsql = ins_file.format(original_name=r.original_name,
                                          filemd5=r.md5FileName,
                                          file_type=r.file_type)
                sqls.append(tempsql)
                tempsql = ins_add.format(archives_pk=cur_pk,
                                         file_pk='({})'.format(
                                             JPDb().LAST_INSERT_ID_SQL()),
                                         file_index=iRow)
                sqls.append(tempsql)

            # 如果没有删除并且是一个已经存在的文件,修改显示顺序
            if r.archives_pk and not r.deleted:
                tempsql = up_index.format(archives_pk=cur_pk,
                                          file_pk=r.file_pk,
                                          file_index=iRow)
                sqls.append(tempsql)

        return sqls