ソースを参照

Merge branch '深圳三院' of http://119.23.210.103:3000/wy/zdqy_firm_former into 深圳三院

zhonghuizhen 11 ヶ月 前
コミット
6d5d144868

+ 51 - 39
src/api/platform/system/news.js

@@ -4,69 +4,81 @@ import { SYSTEM_URL, FORM_URL } from '@/api/baseUrl'
  * 查询列表数据
  * @param {*} params
  */
-export function queryPageList(params) {
-  return request({
-    url: SYSTEM_URL() + '/system/news/query',
-    method: 'post',
-    data: params
-  })
+export function queryPageList (params) {
+    return request({
+        url: SYSTEM_URL() + '/system/news/query',
+        method: 'post',
+        data: params
+    })
 }
 /**
  * 删除数据
  * @param {*} params
  */
-export function remove(params) {
-  return request({
-    url: SYSTEM_URL() + '/system/news/remove',
-    method: 'post',
-    isLoading: true,
-    params: params
-  })
+export function remove (params) {
+    return request({
+        url: SYSTEM_URL() + '/system/news/remove',
+        method: 'post',
+        isLoading: true,
+        params: params
+    })
 }
 /**
  * 保存数据
  * @param {*} params
  */
-export function save(params) {
-  return request({
-    url: SYSTEM_URL() + '/system/news/save',
-    method: 'post',
-    isLoading: true,
-    data: params
-  })
+export function save (params) {
+    return request({
+        url: SYSTEM_URL() + '/system/news/save',
+        method: 'post',
+        isLoading: true,
+        data: params
+    })
 }
 
 /**
  * 获取数据
  * @param {*} params
  */
-export function get(params) {
-  return request({
-    url: SYSTEM_URL() + '/system/news/get',
-    method: 'get',
-    params
-  })
+export function get (params) {
+    return request({
+        url: SYSTEM_URL() + '/system/news/get',
+        method: 'get',
+        params
+    })
 }
 
 /**
  * 推送管理评审通知
  * @param {*} params
  */
-export function manage(params) {
-  return request({
-    url: FORM_URL() + '/audit/notice/manage',
-    method: 'post',
-    data: params
-  })
+export function manage (params) {
+    return request({
+        url: FORM_URL() + '/audit/notice/manage',
+        method: 'post',
+        data: params
+    })
 }
- /**
+/**
  * 推送内审实施计划通知
  * @param {*} params
  */
-export function internal(params) {
-  return request({
-    url: FORM_URL() + '/audit/notice/internal',
-    method: 'post',
-    data: params
-  })
+export function internal (params) {
+    return request({
+        url: FORM_URL() + '/audit/notice/internal',
+        method: 'post',
+        data: params
+    })
+}
+
+/**
+ * 日志数据解析SQL语句
+ * @param {*} params
+ */
+export function dataToSql (params) {
+    return request({
+        url: FORM_URL() + '/audit/notice/log/dataToSql',
+        method: 'get',
+        params
+    })
 }

+ 28 - 29
src/business/platform/bpmn/form/action.js

@@ -750,60 +750,59 @@ export default {
         // 修改流程时间
 
         async handleTimeModification () {
-            // 表单
+            // 获取表单数
             const { code = '', name = '' } = this.getFormEL().formDefData || {}
+            const currentFormData = this.$common.replaceNullWithEmpty(this.getFormData())
             const jsonData = {
                 boCode: code,
                 version: 0,
                 formKey: this.dataResultitem.formKey,
                 pk: this.dataResultitem.bizKey,
-                data: JSON.stringify(this.$common.replaceNullWithEmpty(this.getFormData()))
+                data: JSON.stringify(currentFormData),
+                // 接口新增参数,是否记录操作日志
+                addLog: true
             }
-            // 流程参数
-            const defData = this.formParams.formOpinionData.opinionList
-            // 快照参数
 
+            // 获取流程意见数据
+            const { opinionList, formOpinionNodeData } = this.formParams.formOpinionData || {}
             const snapshot = { id: this.instanceId_ }
 
-            // console.log(JSON.stringify(this.$common.replaceNullWithEmpty(this.formDataBF)), JSON.stringify(this.$common.replaceNullWithEmpty(this.getFormData())))
-            // console.log(this.formDataBF)
-            if (this.timeModification_) {
-                if (JSON.stringify(this.$common.replaceNullWithEmpty(this.formDataBF)) === JSON.stringify(this.$common.replaceNullWithEmpty(this.getFormData()))) {
-                    // console.log('aa')
-                    if (JSON.stringify(defData) === JSON.stringify(this.opinionListBF)) {
-                        // console.log('aa')
-                    } else {
-                        await this.timeModify(defData)
-                    }
-                } else {
-                    if (JSON.stringify(defData) === JSON.stringify(this.opinionListBF)) {
-                        await this.saveData(jsonData, false, defData, snapshot)
-                    } else {
-                        await this.saveData(jsonData, true, defData, snapshot)
-                    }
-                }
-                // this.timeModification_ = false
-            } else {
+            if (!this.timeModification_) {
                 this.timeModification_ = true
+                return
+            }
+
+            // 检查数据变更状态
+            const isFormDataChanged = JSON.stringify(this.$common.replaceNullWithEmpty(this.formDataBF)) !== JSON.stringify(currentFormData)
+            const isOpinionChanged = JSON.stringify(opinionList) !== JSON.stringify(this.opinionListBF)
+
+            const opinionNodeList = Object.values(formOpinionNodeData).filter(Array.isArray).flat()
+            // 根据变更状态执行相应操作
+            if (!isFormDataChanged && isOpinionChanged) {
+                await this.timeModify(opinionNodeList)
+            } else if (isFormDataChanged) {
+                await this.saveData(jsonData, isOpinionChanged, opinionNodeList, snapshot)
             }
         },
         // 保存流程数据生成快照
         async timeModify (data) {
-            await changeCompleteTime(data).then(response => {
+            try {
+                const response = await changeCompleteTime(data)
                 if (response.state === 200) {
                     this.$message.success('修改成功!')
                     this.callbackPage()
                 } else {
                     this.$message.error(response.message)
                 }
-            }).catch(() => {
-            })
+            } catch (error) {
+                console.error('修改时间失败:', error)
+            }
         },
         // 保存表单数据生成快照
-        async saveData (data, sflc, defData, snapshot) {
+        async saveData (data, sflc, opinionList, snapshot) {
             await saveFormData(data).then(response => {
                 if (sflc) {
-                    this.timeModify(defData)
+                    this.timeModify(opinionList)
                 } else {
                     this.repleceSnapshot(snapshot)
                 }

+ 1 - 1
src/business/platform/bpmn/form/index.vue

@@ -468,7 +468,7 @@ export default {
                 // 备份对比
                     this.$nextTick(() => {
                         setTimeout(() => {
-                            this.formDataBF = this.getFormData()
+                            this.formDataBF = JSON.parse(JSON.stringify(this.getFormData()))
                         }, 500)
                         this.opinionListBF = JSON.parse(JSON.stringify(this.formParams.formOpinionData.opinionList))
                     })

+ 1 - 1
src/business/platform/data/templaterender/templates/list.vue

@@ -1021,8 +1021,8 @@ export default {
                         this.search()
                         break
                     case 'add': // 添加
-                        this.handleEdit(null, command, position, selection, data)
                         this.addDataCont = button.initAddDataCont
+                        this.handleEdit(null, command, position, selection, data)
                         break
                     case 'edit': // 编辑
                     case 'detail': // 明细

+ 15 - 4
src/business/platform/form/formrender/dynamic-form/dynamic-form-table.vue

@@ -146,7 +146,7 @@
                                     <el-button-group>
                                         <template v-for="(button, b) in toolbarButtons">
                                             <template v-if="!(button.key === 'remove' && dataModel.length === 1)">
-                                                <el-button :key="b" :type="button.type" :icon="button.icon" @click="handleActionEvent(button, b)">
+                                                <el-button :key="b" :type="button.type" :icon="button.icon" @click="handleActionEvent(button, index)">
                                                     {{ button.label }}
                                                 </el-button>
                                             </template>
@@ -605,6 +605,10 @@ export default {
             if (this.nameColumns && this.nameColumns.length > 0) {
                 this.nameColumns.forEach((column) => {
                     columnsRights[column.name] = 'e'
+                    // 层级组件和子表隐藏字段修改时不显示
+                    if (column.field_type === 'currentPosition' || column.field_options.hide_rights === true || !column.field_options.display) {
+                        columnsRights[column.name] = 'h'
+                    }
                 })
             }
             // console.log(columnsRights)
@@ -781,9 +785,12 @@ export default {
                 // 后置事件
                 this.afterScript(this.actionCode, this.actionPosition)
                 if (this.$refs.elTable) {
+                    this.$refs.elTable.clearSelection()
                     this.$refs.elTable.doLayout()
                 }
-            }).catch(() => {})
+            }).catch((e) => {
+            	this.$refs.elTable?.clearSelection()
+            })
         },
         /**
          * 获取选择的记录
@@ -855,18 +862,22 @@ export default {
                         // this.dataModel.push(data)
                     })
                     // 后置事件
+                    let importCallBack = null
                     if (this.actionCode === 'importData') {
                         this.afterScript(this.actionCode, this.actionPosition, {
                             button: this.actionButton,
                             importList: list,
-                            fullImportList: [...this.dataModel, ...list]
+                            fullImportList: [...this.dataModel, ...list],
+                            importFunction (a) {
+                                importCallBack = a
+                            }
                         })
                     }
 
                     this.importTableDialogVisible = false
                     this.importValue = null
                     this.importList = []
-                    ActionUtils.success('导入成功')
+                    importCallBack ? importCallBack() : ActionUtils.success('导入成功')
                 })
             } else {
                 const formData = FormUtils.getTableDefaultColumnData(this.field)

+ 43 - 32
src/business/platform/form/formrender/dynamic-form/dynamic-form.vue

@@ -142,7 +142,7 @@ export default {
         permissions: {
             type: Object
         },
-        BpmnForm: {
+        bpmnForm: {
             type: Boolean,
             default: false
         },
@@ -268,6 +268,9 @@ export default {
             },
             deep: true,
             immediate: true
+        },
+        timeModification () {
+            this.initResponseFields()
         }
         // models: {
         //     handler (val) {
@@ -304,8 +307,8 @@ export default {
     },
     methods: {
         /**
-             * 初始化字段
-             */
+         * 初始化字段
+         */
         async initResponseFields () {
             let fields
             if (this.formDef && this.formDef.fields) fields = this.formDef.fields
@@ -319,8 +322,8 @@ export default {
             await this.initResponseOpinionData()
         },
         /**
-             * 生成modles
-             */
+         * 生成modles
+         */
         async generateModles (fields) {
             for (let i = 0; i < fields.length; i++) {
                 const field = fields[i]
@@ -406,8 +409,8 @@ export default {
             return data
         },
         /**
-             *  初始化表单扩展参数
-             */
+         *  初始化表单扩展参数
+         */
         initFormFieldParameter (field) {
             // ====== 初始化表单权限
             this.initFormRights(field)
@@ -420,10 +423,18 @@ export default {
             this.rights[field.name] = FormUtils.getDefaultApprovalOpinionRigths(field, this.params) || this.getPermissions(this.permissions, field) || FormUtils.getDefaultRigths(field)
         },
         /**
-             *  初始化表单权限
-             */
+         *  初始化表单权限
+         */
         initFormRights (field) {
-            this.rights[field.name] = this.getPermissions(this.permissions, field) || FormUtils.getDefaultRigths(field)
+            let fieldRights = this.getPermissions(this.permissions, field) || FormUtils.getDefaultRigths(field)
+            const fieldType = field.field_type
+            const isNonInputField = FormOptions.t.NON_INPUT_FIELD_TYPES.includes(fieldType)
+            const specialFields = ['table', 'approval_opinion', 'currentPosition']
+            // 体系运行记录盒修改数据时,主表中,普通字段权限都设置为可编辑
+            if (!isNonInputField && !specialFields.includes(fieldType)) {
+                fieldRights = this.timeModification && fieldRights !== 'h' ? FormOptions.t.PERMISSIONS.EDIT : fieldRights
+            }
+            this.rights[field.name] = fieldRights
         },
         // 获取权限
         getPermissions (permissions, field) {
@@ -446,8 +457,8 @@ export default {
                 isSpecial = true
                 rightsValue = permissions.tables[name] ? permissions.tables[name] : null
             } else {
-                // 字段
-                rightsValue = permissions.fields[name] ? permissions.fields[name] : null
+                // 其他字段
+                rightsValue = permissions.fields[name] || null
             }
             if (this.$route.path === '/xxgl/jssllb') {
                 return rightsValue
@@ -513,8 +524,8 @@ export default {
             }
         },
         /**
-             * 表单提交校验
-             */
+         * 表单提交校验
+         */
         formSubmitVerify (callback) {
             let flag = true
             const verifys = this.formAttrs ? this.formAttrs.verifys : []
@@ -535,8 +546,8 @@ export default {
             callback(flag)
         },
         /**
-             * 获取表单数据
-             */
+         * 获取表单数据
+         */
         getFormData () {
             const data = {}
             // 去除文本字段,表单意见字段
@@ -548,32 +559,32 @@ export default {
             return data
         },
         /**
-             * 设置表单字段数据
-             */
+         * 设置表单字段数据
+         */
         setFieldData (name, value) {
             this.models[name] = value
         },
         /**
-             * 设置表单权限
-             */
+         * 设置表单权限
+         */
         getFormRights (name) {
             return this.rights[name]
         },
         /**
-             * 设置表单权限
-             */
+         * 设置表单权限
+         */
         setFormRights (name, value) {
             this.rights[name] = value
         },
         /**
-             *  是否有审批意见字段
-             */
+         *  是否有审批意见字段
+         */
         hasFormOpinion () {
             return this.$utils.isNotEmpty(this.responseOpinionFields)
         },
         /**
-             * 获取审批意见数据
-             */
+         * 获取审批意见数据
+         */
         getFormOpinionData () {
             const data = {}
             for (var key in this.models) {
@@ -584,8 +595,8 @@ export default {
             return data
         },
         /**
-             * 获取审批意见验证
-             */
+         * 获取审批意见验证
+         */
         formOpinionValidate (callback, flag = false) {
             if (this.$utils.isEmpty(this.responseOpinionFields)) {
                 callback(true)
@@ -613,8 +624,8 @@ export default {
             }
         },
         /**
-             * 表单验证
-             */
+         * 表单验证
+         */
         validate (callback) {
             // 先移除校验再进行校验
             this.$refs.form.clearValidate()
@@ -632,8 +643,8 @@ export default {
             this.record = type
         }
         /**
-             * 获取表单字段的具体控件组件实例
-             */
+         * 获取表单字段的具体控件组件实例
+         */
         // getRefsField (fieldName) {
         //     const refs = this.getRefs(fieldName)
         //     if (this.$utils.isEmpty(refs) || this.$utils.isEmpty(refs[0]) || this.$utils.isEmpty(refs[0].$refs) || this.$utils.isEmpty(refs[0].$refs['formField'])) {

+ 2 - 1
src/business/platform/form/utils/custom/joinCURD.js

@@ -3,6 +3,7 @@ import { normal } from './requestType'
 import { encryptByAes } from '@/utils/encrypt'
 import { mapValues } from 'lodash'
 import { SHOW_PLAINTEXT } from '@/constant'
+import { getToken } from '@/utils/auth'
 // 请求方式默认POST
 const post = (type, data, method = 'post', loading = false) => {
     const requestUrl = `business/v3/sys/universal/${normal[type]}`
@@ -45,7 +46,7 @@ const dealData = (args, type) => {
     const data = typeof args === 'object' ? replaceNullWithEmpty(args) : args
     const plaintext = SHOW_PLAINTEXT ? { plaintext: data } : {}
     const res = {
-        ciphertext: encryptByAes(data),
+        ciphertext: encryptByAes(data, 'dynamic', getToken()),
         ...plaintext
     }
     return JSON.stringify(res)

+ 5 - 0
src/components/ibps-crud/index.vue

@@ -540,4 +540,9 @@ export default {
         display: flex;
         flex-wrap: wrap;
     }
+    /* 表单组件渲染时计算表单高度受转换元素影响(附件、人员、部门等) */
+    .elTable .el-table__body-wrapper{
+        height: v-bind(tableHeight);
+        overflow-y: auto;
+    }
 </style>

+ 29 - 2
src/components/ibps-fullcalendar/index.vue

@@ -27,14 +27,25 @@ export default {
     props: {
         options: {
             type: Object,
-            default: () => {}
+            default: () => ({})
+        },
+        // 新增配置项:是否隐藏其他月份日期
+        hideOtherMonthDays: {
+            type: Boolean,
+            default: false
         }
     },
     data () {
         return {
             calendarOptions: {
                 plugins: [dayGridPlugin, timeGridPlugin, listPlugin, bootstrapPlugin, interactionPlugin],
-                initialView: 'dayGridMonth'
+                initialView: 'dayGridMonth',
+                fixedWeekCount: false,
+                views: {
+                    dayGridMonth: {
+                        showNonCurrentDates: !this.hideOtherMonthDays // 是否隐藏非当前月日期
+                    }
+                }
             }
         }
     },
@@ -49,6 +60,22 @@ export default {
         locale () {
             return lang.localeMap[I18n.getLanguage()]
         }
+    },
+    watch: {
+        hideOtherMonthDays: {
+            handler (newVal) {
+                const calendarApi = this.$refs.fullCalendar?.getApi()
+                if (calendarApi) {
+                    calendarApi.setOption('views', {
+                        dayGridMonth: {
+                            showNonCurrentDates: !this.hideOtherMonthDays // 根据 prop 反转逻辑
+                        }
+                    })
+                    calendarApi.render() // 强制重新渲染
+                }
+            },
+            immediate: true
+        }
     }
 }
 </script>

+ 3 - 1
src/store/getters.js

@@ -41,5 +41,7 @@ export default {
     // 获取用户最高层级
     level: state => state.ibps.param && state.ibps.param.level ? state.ibps.param.level : [],
     // 获取认证信息
-    licence: state => state.ibps.licence ? state.ibps.licence.licJson : {}
+    licence: state => state.ibps.licence ? state.ibps.licence.licJson : {},
+    // 获取配置信息
+    setting: state => state.ibps.param && state.ibps.param.setting ? state.ibps.param.setting : {}
 }

+ 9 - 1
src/store/modules/ibps/modules/param.js

@@ -11,7 +11,9 @@ export default {
         level: {
             first: '',
             second: ''
-        }
+        },
+        // 配置信息
+        setting: {}
     },
     mutations: {
         myformSet (state, myform) {
@@ -25,6 +27,9 @@ export default {
         },
         level (state, data) {
             state.level = data || { first: '', second: '' }
+        },
+        setting (state, data) {
+            state.setting = data || {}
         }
     },
     actions: {
@@ -34,6 +39,9 @@ export default {
         setDeptList ({ commit }, data) {
             commit('deptList', data)
         },
+        setSetting ({ commit }, data) {
+            commit('setting', data)
+        },
         setLevel ({ commit }, data) {
             console.log(data)
             commit('level', data)

+ 5 - 1
src/store/modules/ibps/modules/user.js

@@ -92,6 +92,10 @@ export default {
                                 root: true
                             })
                         }
+                        // 获取所有配置信息
+                        await dispatch('ibps/param/setSetting', await getSetting(), {
+                            root: true
+                        })
                         // 获取所有用户信息
                         await dispatch('getUserList', level)
                         // 获取所有部门信息
@@ -102,7 +106,7 @@ export default {
                         })
                         // 尝试从配置数据中获取 否则使用默认
                         const highRoles = await getSetting('system', 'highRoles')
-                        highRoles && (info.highRoles = highRoles)
+                        Utils.isNotEmpty(highRoles) && (info.highRoles = highRoles)
                         const { role = [] } = info || {}
                         const hasHighRole = role.some(item => info.highRoles.includes(item.alias))
                         // 用于文件预览页判定是否开启下载权限

+ 146 - 33
src/utils/encrypt.js

@@ -1,45 +1,158 @@
 import CryptoJS from 'crypto-js'
+const key = '49PBou+TREIOzSHj'
 const key1 = CryptoJS.enc.Utf8.parse('dmngJmmO+9GMw+tu')
-const iv1 = CryptoJS.enc.Utf8.parse('sanXyqhk8+U7LPP4')
-const key2 = CryptoJS.enc.Utf8.parse('49PBou+TREIOzSHj')
-const iv2 = CryptoJS.enc.Utf8.parse('5lDsNRe&UduJ97uS')
+const key2 = CryptoJS.enc.Utf8.parse(key)
+// 固定IV 用于密码、get请求参数加密
+const defaultIv = CryptoJS.enc.Utf8.parse('5lDsNRe&UduJ97uS')
 
-// AES加密
-export const encryptByAes = (pwd, type = 'normal') => {
+// 密钥派生参数配置
+const PBKDF2_CONFIG = {
+    // 盐值长度(bits)
+    saltSize: 128,
+    // 迭代次数
+    iterations: 10000,
+    // 密钥长度(256bit)
+    keySize: 256 / 32,
+    hashAlgorithm: CryptoJS.algo.SHA256
+}
+
+// 动态密钥派生器
+const deriveDynamicKey = (token, salt) => {
+    if (!token || typeof token !== 'string') {
+        throw new Error('Invalid user token')
+    }
+
+    return CryptoJS.PBKDF2(token, salt, {
+        keySize: PBKDF2_CONFIG.keySize,
+        iterations: PBKDF2_CONFIG.iterations,
+        hasher: PBKDF2_CONFIG.hashAlgorithm
+    })
+}
+
+// 动态IV生成器
+export const generateDynamicIV = () => {
+    // 1. 获取当前时间戳(8字节,64位)
+    const timestamp = Date.now()
+    // 将时间戳转换为8字节的WordArray(大端序)
+    const timestampBytes = CryptoJS.enc.Hex.parse(
+        timestamp.toString(16).padStart(16, '0')
+    )
+
+    // 2. 生成8字节随机数
+    const randomBytes = CryptoJS.lib.WordArray.random(8)
+
+    // 3. 构造IV(16字节)
+    const ivWords = [
+        // 前4字节:随机数的高4字节
+        randomBytes.words[0],
+        // 接下来4字节:时间戳的高4字节
+        timestampBytes.words[0],
+        // 接下来4字节:随机数的低4字节
+        randomBytes.words[1],
+        // 最后4字节:时间戳的低4字节
+        timestampBytes.words[1]
+    ]
+
+    return CryptoJS.lib.WordArray.create(ivWords, 16)
+}
+
+const xorEncrypt = (text) => {
     let encrypted = ''
-    const key = type === 'normal' ? key1 : key2
-    const iv = type === 'normal' ? iv1 : iv2
-    if (typeof pwd === 'string') {
-        const srcs = CryptoJS.enc.Utf8.parse(pwd)
-        const options = {
-            iv: iv,
-            mode: CryptoJS.mode.CBC, // 使用CBC模式
-            padding: CryptoJS.pad.Pkcs7 // 使用PKCS7填充
-        }
-        encrypted = CryptoJS.AES.encrypt(srcs, key, options)
-    } else if (typeof pwd === 'object') {
-        const data = JSON.stringify(pwd)
+    for (let i = 0; i < text.length; i++) {
+        const charCode = text.charCodeAt(i) ^ key.charCodeAt(i % key.length)
+        encrypted += String.fromCharCode(charCode)
+    }
+
+    return btoa(encrypted)
+}
+
+const xorDecrypt = (encryptedBase64) => {
+    // 从Base64解码
+    const decodedStr = atob(encryptedBase64)
+    let decrypted = ''
+
+    // 异或解密
+    for (let i = 0; i < decodedStr.length; i++) {
+        const charCode = decodedStr.charCodeAt(i) ^ key.charCodeAt(i % key.length)
+        decrypted += String.fromCharCode(charCode)
+    }
+
+    return decrypted
+}
+
+// AES加密
+export const encryptByAes = (params, type = 'dynamic', token) => {
+    try {
+        const isDynamic = type === 'dynamic'
+        // 生成随机盐值
+        const salt = CryptoJS.lib.WordArray.random(PBKDF2_CONFIG.saltSize)
+        // 动态派生密钥
+        const derivedKey = isDynamic ? deriveDynamicKey(token, salt) : key2
+        // 生成动态iv
+        const iv = isDynamic ? generateDynamicIV() : defaultIv
+        const data = typeof params === 'string' ? params : JSON.stringify(params)
         const srcs = CryptoJS.enc.Utf8.parse(data)
-        const options = {
+
+        const encrypted = CryptoJS.AES.encrypt(srcs, derivedKey, {
             iv: iv,
-            mode: CryptoJS.mode.CBC, // 使用CBC模式
-            padding: CryptoJS.pad.Pkcs7 // 使用PKCS7填充
+            mode: CryptoJS.mode.CBC,
+            padding: CryptoJS.pad.Pkcs7
+        })
+
+        if (isDynamic) {
+            const str = encrypted.ciphertext.toString(CryptoJS.enc.Base64) + '|' + iv.toString(CryptoJS.enc.Base64) + '|' + salt.toString(CryptoJS.enc.Base64) + '|' + token
+            return xorEncrypt(str)
         }
-        encrypted = CryptoJS.AES.encrypt(srcs, key, options)
+        return encrypted.ciphertext.toString(CryptoJS.enc.Base64)
+    } catch (error) {
+        console.error('Encryption error:', error)
+        throw new Error('Encryption failed')
     }
-    return encrypted.ciphertext.toString(CryptoJS.enc.Base64)
 }
 
-export const decryptByAes = (encryptedText, type = 'normal') => {
-    const key = type === 'normal' ? key1 : key2
-    const iv = type === 'normal' ? iv1 : iv2
-    const options = {
-        iv: iv,
-        mode: CryptoJS.mode.CBC, // 使用CBC模式
-        padding: CryptoJS.pad.Pkcs7 // 使用PKCS7填充
+const isValidBase64 = (str) => {
+    try {
+        return btoa(atob(str)) === str
+    } catch (e) {
+        return false
+    }
+}
+
+export const decryptByAes = (ciphertext) => {
+    try {
+        // 初始化解密参数
+        let cipherToDecrypt = ciphertext
+        let iv = defaultIv
+        let key = key2
+
+        // 尝试XOR解密并解析参数
+        const decryptedStr = xorDecrypt(ciphertext)
+        const parts = decryptedStr.split('|')
+        if (parts.length === 4) {
+            const [ciphertextBase64, ivBase64, saltBase64, token] = parts
+
+            if (token && !(isValidBase64(ivBase64) && isValidBase64(saltBase64))) {
+                console.error('解密失败: 无效的IV参数或salt参数!')
+                return ''
+            }
+            // 转换编码
+            iv = CryptoJS.enc.Base64.parse(ivBase64)
+            const salt = CryptoJS.enc.Base64.parse(saltBase64)
+            // 动态派生密钥
+            key = deriveDynamicKey(token, salt)
+            cipherToDecrypt = ciphertextBase64
+        }
+
+        // 解密
+        const decrypted = CryptoJS.AES.decrypt(
+            { ciphertext: CryptoJS.enc.Base64.parse(cipherToDecrypt) },
+            key,
+            { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
+        )
+
+        return decrypted.toString(CryptoJS.enc.Utf8).trim()
+    } catch (error) {
+        console.error('AES解密失败:', error)
+        return ''
     }
-    const encryptedData = CryptoJS.enc.Base64.parse(encryptedText)
-    const decryptedData = CryptoJS.AES.decrypt({ ciphertext: encryptedData }, key, options)
-    const decryptedText = decryptedData.toString(CryptoJS.enc.Utf8)
-    return decryptedText.trim()
 }

+ 17 - 12
src/utils/query.js

@@ -135,20 +135,25 @@ export const getSetting = async (module = '', key = '') => {
         const org = store.getters.level.first || ''
         const sql = `select setting from t_ipcc where org_ = '${org}' limit 1`
         const { variables: { data = [] } = {}} = await request('sql', sql)
-        if (data.length > 0 && data[0]?.setting) {
-            const setting = data[0].setting?.replace(/\n/g, '')
-            const res = JSON.parse(setting)
-            // 根据module和key的存在情况返回不同的结果
-            if (module !== '') {
-                if (key !== '') {
-                    return res?.[module]?.[key]
-                }
-                return res?.[module]
-            }
-            return res
+
+        // 如果数据为空或 setting 字段不存在,直接返回空对象
+        if (data.length === 0 || !data[0]?.setting) {
+            return {}
         }
-        return null
+
+        // 解析 JSON 并处理可能的格式错误
+        const setting = data[0].setting?.replace(/\n/g, '')
+        const res = JSON.parse(setting) || {}
+
+        // 根据 module 和 key 返回对应的值
+        if (module) {
+            const moduleSettings = res[module] || {}
+            return key ? moduleSettings[key] : moduleSettings
+        }
+
+        return res || {}
     } catch (error) {
+        console.error('获取配置失败:', error)
         return Message.warning('数据库字段配置错误!')
     }
 }

+ 2 - 2
src/utils/request.js

@@ -97,7 +97,7 @@ service.interceptors.request.use(async config => {
     if (config.method.toUpperCase() === 'GET') {
         if (ENCRYPT_GET_PARAMS) {
             config.params = {
-                _p: Utils.isNotEmpty(config.params) ? encryptByAes(JSON.stringify(config.params)) : undefined,
+                _p: Utils.isNotEmpty(config.params) ? encryptByAes(JSON.stringify(config.params), 'get') : undefined,
                 _t: new Ids([32, 36, 1]).next()
             }
         } else {
@@ -277,4 +277,4 @@ service.interceptors.response.use(response => {
     return Promise.reject(error)
 })
 
-export default service
+export default service

+ 11 - 10
src/views/component/device/deviceDialog.vue

@@ -572,7 +572,7 @@
                                             <el-col :span="8">
                                                 <el-row>
                                                     <el-col>
-                                                        <el-form-item label="是否校准:" prop="shiFouXiaoZhun">
+                                                        <el-form-item label="是否校准:" prop="shiFouXiaoZhun" label-width="140px">
                                                             <el-select v-if="!readonly" v-model="form.shiFouXiaoZhun" placeholder="请选择" size="mini" style="width:100%">
                                                                 <el-option
                                                                     v-for="item in ['是','否']"
@@ -588,7 +588,7 @@
                                                 </el-row>
                                                 <el-row v-if="form.shiFouXiaoZhun==='是'">
                                                     <el-col>
-                                                        <el-form-item label="检定/校准周期(月):" label-width="140">
+                                                        <el-form-item label="检定/校准周期(月):" label-width="140px">
                                                             <el-input v-if="!readonly" v-model="form.xiaoZhunZQ" size="mini" type="number" style="width:100%" />
                                                             <span v-else>{{ form.xiaoZhunZQ ||'/' }}
                                                             </span>
@@ -597,7 +597,7 @@
                                                 </el-row>
                                                 <el-row v-if="form.shiFouXiaoZhun==='是'">
                                                     <el-col>
-                                                        <el-form-item label="检定/校准单位:">
+                                                        <el-form-item label="检定/校准单位:" label-width="140px">
                                                             <ibps-custom-dialog
                                                                 v-model="form.shiYongKeShi"
                                                                 size="mini"
@@ -614,7 +614,7 @@
                                                 </el-row>
                                                 <el-row v-if="form.shiFouXiaoZhun==='是'">
                                                     <el-col>
-                                                        <el-form-item label="最近校准时间:">
+                                                        <el-form-item label="最近校准时间:" label-width="140px">
                                                             <el-date-picker
                                                                 v-if="!readonly"
                                                                 v-model="form.yiXiaoRiQi"
@@ -632,7 +632,7 @@
                                                 </el-row>
                                                 <el-row v-if="form.shiFouXiaoZhun==='是'">
                                                     <el-col>
-                                                        <el-form-item label="校准有效期至:">
+                                                        <el-form-item label="检定/校准有效期至:" label-width="140px">
                                                             <el-date-picker
                                                                 v-if="!readonly"
                                                                 v-model="form.xiaoZhunYouXia"
@@ -650,7 +650,7 @@
                                                 </el-row>
                                                 <el-row v-if="form.shiFouXiaoZhun==='是'">
                                                     <el-col>
-                                                        <el-form-item label="校准证书编号:">
+                                                        <el-form-item label="检定/校准证书编号:" label-width="140px">
                                                             <el-input v-if="!readonly" v-model="form.zhengShuBianHa" size="mini" />
                                                             <span v-else>{{ form.zhengShuBianHa ||'/' }}
                                                             </span>
@@ -1030,7 +1030,8 @@ export default {
                 if (!val) return
                 const sql = `select fang_jian_ming_ha from t_jjqfjb where id_='${val}'`
                 const { variables: { data }} = await this.$common.request('sql', sql)
-                this.form.cunFangDiDian = data[0].fang_jian_ming_ha
+
+                this.form.cunFangDiDian = data && data[0] ? data[0].fang_jian_ming_ha : ''
             }
         },
         // 根据编制部门动态获取对应文件存放处数据
@@ -1053,9 +1054,9 @@ export default {
                         this.isFirstyiXiaoRiQi = false
                         return
                     }
-                    const zhouQi = this.form.xiaoZhunZQ || 0
-                    const result = this.$common.getFormatDate('string', 10, this.$common.getDate('month', Number(zhouQi), value))
-                    this.form.xiaoZhunYouXia = result
+                    const cycle = this.form.xiaoZhunZQ || 0
+                    const expiredDate = this.$common.getFormatDate('string', 10, this.$common.getDate('month', parseInt(cycle), value))
+                    this.form.xiaoZhunYouXia = this.$common.getFormatDate('string', 10, this.$common.getDate('day', -1, expiredDate))
                 }
             }
         }

+ 24 - 4
src/views/component/device/index.vue

@@ -299,8 +299,21 @@
                             />
                         </el-select>
                     </template>
-                    <template slot="place">
+                    <!-- <template slot="place">
                         <el-input v-model="search.place" size="mini" />
+                    </template> -->
+                    <template slot="place">
+                        <ibps-custom-dialog
+                            v-model="search.place"
+                            size="mini"
+                            template-key="fjxzkdd"
+                            multiple
+                            :disabled="false"
+                            type="dialog"
+                            class="custom-dialog"
+                            placeholder="请选择"
+                            icon="el-icon-search"
+                        />
                     </template>
                     <template slot="managePeople">
                         <ibps-user-selector
@@ -769,9 +782,16 @@ export default {
                 parameters.parameters.push(obj)
             }
             // 放置地点搜索
+            // if (this.search.place) {
+            //     const obj = { relation: 'AND', parameters: [] }
+            //     obj.parameters.push({ key: 'Q^cun_fang_di_dian_^SL', value: this.search.place, param: this.$utils.guid() })
+            //     parameters.parameters.push(obj)
+            // }
             if (this.search.place) {
-                const obj = { relation: 'AND', parameters: [] }
-                obj.parameters.push({ key: 'Q^cun_fang_di_dian_^SL', value: this.search.place, param: this.$utils.guid() })
+                const obj = { relation: 'OR', parameters: [] }
+                this.search.place.split(',').forEach(item => {
+                    obj.parameters.push({ key: 'Q^cun_fang_wei_zhi_^S', value: item, param: this.$utils.guid() })
+                })
                 parameters.parameters.push(obj)
             }
             // 保管人搜索(可多选)
@@ -786,7 +806,7 @@ export default {
             if (this.search.deviceClass) {
                 const obj = { relation: 'OR', parameters: [] }
                 this.search.deviceClass.split(',').forEach(item => {
-                    obj.parameters.push({ key: 'Q^wei_hu_fang_shi_^S', value: item, param: this.$utils.guid() })
+                    obj.parameters.push({ key: 'Q^wei_hu_fang_shi_^SL', value: item, param: this.$utils.guid() })
                 })
                 parameters.parameters.push(obj)
             }

+ 551 - 0
src/views/component/newReagent/newReagent.vue

@@ -0,0 +1,551 @@
+<template>
+    <div>
+        <div v-if="show" class="reagentChange">
+            <el-row type="flex">
+                <el-col class="button">
+                    <div class="title">平行实验/留样再测</div>
+                    <div v-if="nodeId === 'Activity_0xkc1ji' || readonly" />
+                    <div v-else>
+                        <span style="color: red;margin-right: 20px;font-size: 16px;">注意:手动计算与导入不可混用</span>
+                        <el-button type="primary" size="mini" icon="ibps-icon-add" @click="handleAdd"> 添加</el-button>
+                        <el-button type="primary" size="mini" icon="ibps-icon-copy" @click="handleCopy"> 复制</el-button>
+                        <el-button type="danger" size="mini" icon="ibps-icon-remove" @click="handleDelete"> 删除</el-button>
+                        <el-button type="warning" size="mini" icon="ibps-icon-calculator" @click="computedResult">计算</el-button>
+                        <el-button type="primary" size="mini" icon="ibps-icon-download" @click="handleDownload">模版下载</el-button>
+                        <el-button type="primary" size="mini" icon="ibps-icon-import" @click="handleImport">导入</el-button>
+                    </div>
+                </el-col>
+            </el-row>
+            <el-row type="flex">
+                <el-col>
+                    <el-table ref="reagent" :data="reagentDataFilter" :span-method="spanMethod" @selection-change="handleSelectionChange">
+                        <el-table-column type="selection" width="55" />
+                        <el-table-column
+                            label="检验项目"
+                            prop="jianCeXiangMu"
+                        />
+                        <el-table-column label="浓度" prop="nongDu" width="100">
+                            <template slot-scope="{row}">
+                                <el-input v-if="!disabled" v-model="row.nongDu" size="mini" placeholder="请输入" />
+                                <span v-else>{{ row.nongDu|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="样品编号" prop="biaoBenHao" width="100">
+                            <template slot-scope="{row}">
+                                <el-input v-if="!disabled" v-model="row.biaoBenHao" size="mini" placeholder="请输入" />
+                                <span v-else>{{ row.biaoBenHao|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="旧试剂测得结果" prop="jiuJieGuo" width="130">
+                            <template slot-scope="{row}">
+                                <el-input v-if="!disabled" v-model="row.jiuJieGuo" :min="0" size="mini" placeholder="请输入" type="number" />
+                                <span v-else>{{ row.jiuJieGuo|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="新试剂测得结果" prop="xinJieGuo" width="130">
+                            <template slot-scope="{row}">
+                                <el-input v-if="!disabled" v-model="row.xinJieGuo" :min="0" size="mini" placeholder="请输入" type="number" />
+                                <span v-else>{{ row.xinJieGuo|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="计算方式" prop="jiSuanFangShi" width="140">
+                            <template slot-scope="{row}">
+                                <el-select v-if="!disabled" v-model="row.jiSuanFangShi" size="mini" placeholder="请选择">
+                                    <el-option
+                                        label="|Y-X|"
+                                        value="|Y-X|"
+                                    />
+                                    <el-option
+                                        label="|Y-X|/X(%)"
+                                        value="|Y-X|/X(%)"
+                                    />
+                                </el-select>
+                                <span v-else>{{ row.jiSuanFangShi|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="实际差值" prop="shiJiChaZhi" />
+                        <el-table-column label="实际偏倚" prop="jieGuo" />
+                        <el-table-column :label="isHz?'允许差值':'限定范围'" prop="zuiXiaoFanWei" width="110">
+                            <template slot-scope="{row}">
+                                <el-input v-if="!disabled" v-model="row.zuiXiaoFanWei" size="mini" placeholder="请输入" type="number" />
+                                <span v-else>{{ row.zuiXiaoFanWei|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="允许偏倚" prop="yunXuPianYi" width="100">
+                            <template slot-scope="{row}">
+                                <el-input v-if="!disabled" v-model="row.yunXuPianYi" size="mini" placeholder="请输入" />
+                                <span v-else>{{ row.yunXuPianYi|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="是否相符" prop="xiangFu" width="80" />
+                        <el-table-column label="符合率" prop="biaoZhun" />
+                        <el-table-column label="符合率可接受标准" prop="xiangMuFuHeLv" width="140">
+                            <template slot-scope="{row}">
+                                <el-select v-if="!disabled" v-model="row.xiangMuFuHeLv" size="mini" placeholder="请选择" @change="handelChange($event,row.jianCeXiangMu)">
+                                    <el-option
+                                        label="≥80%"
+                                        value="≥80%"
+                                    />
+                                    <el-option
+                                        label="=100%"
+                                        value="=100%"
+                                    />
+                                </el-select>
+                                <span v-else>{{ row.xiangMuFuHeLv|| '/' }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="结论" prop="jieLun" />
+                    </el-table>
+                    <el-pagination
+                        layout="total,sizes,prev, pager, next,jumper"
+                        :current-page="requestPage.pageNo"
+                        :page-size="requestPage.limit"
+                        :page-sizes="[10,15,20,30,50,100]"
+                        :total="reagentData.length"
+                        @size-change="handleSizeChange"
+                        @current-change="handleCurrentChange"
+                    />
+                </el-col>
+            </el-row>
+        </div>
+        <import-table
+            :visible="importTableDialogVisible"
+            title="导入"
+            @close="(visible) => (importTableDialogVisible = visible)"
+            @action-event="handleImportTableActionEvent"
+        />
+    </div>
+</template>
+<script>
+import importTable from '@/business/platform/form/formrender/dynamic-form/components/import-table'
+import IbpsImport from '@/plugins/import'
+import { downloadFile } from '@/business/platform/file/utils'
+import { cloneDeep } from 'lodash'
+export default {
+    components: {
+        importTable
+    },
+    props: {
+        formData: {
+            type: Object,
+            default: () => {}
+        },
+        readonly: {
+            type: Boolean,
+            default: false
+        },
+        params: {
+            type: Object,
+            default: () => {}
+        }
+    },
+    data () {
+        return {
+            reagentData: [],
+            copyDialogData: [],
+            disabled: false,
+            ypData: [],
+            nodeId: '',
+            show: true,
+            requestPage: {
+                limit: 20,
+                pageNo: 1
+            },
+            importTableDialogVisible: false,
+            multipleSelection: [],
+            isHz: false
+        }
+    },
+    computed: {
+        reagentDataFilter () {
+            return this.reagentData.slice((this.requestPage.pageNo - 1) * (this.requestPage.limit), (this.requestPage.pageNo - 1) * (this.requestPage.limit) + this.requestPage.limit)
+        }
+    },
+    watch: {
+        'formData.sjghyzjlbbbzb': {
+            handler (value, old) {
+                if (value && value.length) {
+                    this.reagentData = value
+                }
+            },
+            immediate: true
+        },
+        reagentData: {
+            handler (value, old) {
+                this.$emit('change-data', 'sjghyzjlbbbzb', value)
+            },
+            deep: true
+        },
+        'formData.fangAn': {
+            handler (val) {
+                this.showAndHide(val)
+            },
+            immediate: true
+        },
+        'formData.yunXuPianYi': {
+            handler (val) {
+                this.reagentData.forEach(item => {
+                    const { jianYanXiangMu } = this.formData
+                    if (item.jianCeXiangMu === jianYanXiangMu) {
+                        item.yunXuPianYi = val
+                    }
+                })
+            },
+            immediate: true
+        },
+        'formData.xianDingFanWei': {
+            handler (val) {
+                this.reagentData.forEach(item => {
+                    const { jianYanXiangMu } = this.formData
+                    if (item.jianCeXiangMu === jianYanXiangMu) {
+                        item.zuiXiaoFanWei = val
+                    }
+                })
+            }
+        }
+    },
+    mounted () {
+        const { first = '' } = this.$store.getters.level
+        const { deptList = [] } = this.$store.getters || {}
+        const t1 = deptList.find(i => i.positionId === first) || {}
+        this.isHz = t1.positionName === '惠州市第三人民医院'
+        console.log(t1.positionName)
+        this.nodeId = this.params ? this.params.nodeId : ''
+        this.disabled = this.readonly || this.nodeId === 'Activity_0xkc1ji'
+        this.showAndHide(this.formData.fangAn)
+    },
+    methods: {
+        handelChange (event, jianCeXiangMu) {
+            this.reagentData.forEach(item => {
+                if (item.jianCeXiangMu == jianCeXiangMu) {
+                    item.xiangMuFuHeLv = event
+                }
+            })
+        },
+        // 新增
+        handleAdd () {
+            const { jianYanXiangMu, yunXuPianYi, xianDingFanWei } = this.formData
+            if (this.disabled && this.reagentData?.length > 0) {
+                return this.$message.warning('导入与手动添加功能不可混用!')
+            }
+            if (!this.formData.jianYanXiangMu) {
+                return this.$message.warning('请选择检验项目')
+            }
+            this.reagentData.push({ jianCeXiangMu: jianYanXiangMu, nongDu: '', biaoBenHao: '', jiuJieGuo: '', xinJieGuo: '', jiSuanFangShi: '|Y-X|/X(%)', shiJiChaZhi: '', jieGuo: '', zuiXiaoFanWei: xianDingFanWei, yunXuPianYi: yunXuPianYi, xiangFu: '', biaoZhun: '', xiangMuFuHeLv: '≥80%', jieLun: '' })
+            const grouped = this.reagentData.reduce((acc, item) => {
+                const key = item.jianCeXiangMu
+                if (!acc[key]) acc[key] = []
+                acc[key].push(item)
+                return acc
+            }, {})
+            // 先清空数组,再填充新数据(确保 Vue 检测到变化)
+            this.reagentData.splice(0, this.reagentData.length, ...Object.values(grouped).flat())
+            console.log(this.reagentData)
+        },
+        // 复制
+        handleCopy () {
+            if (this.multipleSelection.length > 0) {
+                this.reagentData = this.reagentData.concat(cloneDeep(this.multipleSelection))
+                const grouped = this.reagentData.reduce((acc, item) => {
+                    const key = item.jianCeXiangMu
+                    if (!acc[key]) acc[key] = []
+                    acc[key].push(item)
+                    return acc
+                }, {})
+                // 先清空数组,再填充新数据(确保 Vue 检测到变化)
+                this.reagentData.splice(0, this.reagentData.length, ...Object.values(grouped).flat())
+            } else {
+                this.$message.warning('请选择数据')
+            }
+        },
+        // 删除
+        handleDelete () {
+            this.$confirm('确定删除当前选中数据?', '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(() => {
+                if (this.multipleSelection.length > 0) {
+                    this.reagentData = this.reagentData.filter(row => !this.multipleSelection.includes(row))
+                } else {
+                    this.$message.warning('请选择数据')
+                }
+            })
+        },
+        handleSelectionChange (val) {
+            this.multipleSelection = val
+        },
+        handleImport () {
+            this.importTableDialogVisible = true
+        },
+        handleDownload () {
+            downloadFile({ id: 'download_sjghdl', fileName: '试剂更换验证定量模板', ext: 'xlsx' })
+        },
+        getColumns () {
+            return [{
+                field_name: 'xiangFu',
+                label: '是否相符',
+                name: 'xiangFu'
+            },
+            {
+                field_name: 'jianCeXiangMu',
+                label: '检验项目',
+                name: 'jianCeXiangMu'
+            },
+            {
+                field_name: 'nongDu',
+                label: '浓度',
+                name: 'nongDu'
+            },
+            {
+                field_name: 'biaoBenHao',
+                label: '样品编号',
+                name: 'biaoBenHao'
+            },
+            {
+                field_name: 'jiuJieGuo',
+                label: '旧试剂测得结果',
+                name: 'jiuJieGuo'
+            },
+            {
+                field_name: 'xinJieGuo',
+                label: '新试剂测得结果',
+                name: 'xinJieGuo'
+            },
+            {
+                field_name: 'shiJiChaZhi',
+                label: '实际差值',
+                name: 'shiJiChaZhi'
+            },
+            {
+                field_name: 'jieGuo',
+                label: '实际偏倚',
+                name: 'jieGuo'
+            },
+            {
+                field_name: 'zuiXiaoFanWei',
+                label: this.isHz ? '允许差值' : '限定范围',
+                name: 'zuiXiaoFanWei'
+            },
+            {
+                field_name: 'yunXuPianYi',
+                label: '允许偏倚',
+                name: 'yunXuPianYi'
+            },
+            {
+                field_name: 'biaoZhun',
+                label: '符合率',
+                name: 'biaoZhun'
+            }, {
+                field_name: 'jieLun',
+                label: '结论',
+                name: 'jieLun'
+            },
+            {
+                field_name: 'xiangMuFuHeLv',
+                label: '符合率可接受标准',
+                name: 'xiangMuFuHeLv'
+            }]
+        },
+        getKeys (data) {
+            return Array.isArray(data) ? data.reduce((acc, item) => ({ ...acc, [item.label]: item.name }), {}) : {}
+        },
+        handleImportTableActionEvent (file, options) {
+            IbpsImport.xlsx(file, options).then(({ header, results }) => {
+                const list = []
+                const keys = this.getKeys(this.getColumns())
+                results.forEach(item => {
+                    const obj = {}
+                    Object.keys(item).forEach(key => {
+                        if (keys[key]) {
+                            obj[keys[key]] = item[key]
+                        }
+                    })
+                    list.push(obj)
+                })
+                const filteredArray = list.map(item => {
+                    if (item.jianCeXiangMu && item.biaoZhun && item.jieLun) {
+                        return item
+                    }
+                    return null
+                }).filter(item => item !== null)
+                filteredArray.forEach(item => {
+                    list.forEach(el => {
+                        if (el.jianCeXiangMu === item.jianCeXiangMu) {
+                            el.biaoZhun = item.biaoZhun
+                            el.jieLun = item.jieLun
+                            el.xiangMuFuHeLv = item.xiangMuFuHeLv
+                        }
+                        if (el.shiJiChaZhi) {
+                            el.shiJiChaZhi = (el.shiJiChaZhi + '').replace('-', '')
+                        }
+                        if (el.jieGuo) {
+                            el.jieGuo = (el.jieGuo + '').replace('-', '')
+                        }
+                    })
+                })
+                this.reagentData = list
+                this.disabled = true
+                this.importTableDialogVisible = false
+            })
+        },
+        // 当前页码改变
+        handleCurrentChange (val) {
+            this.requestPage.pageNo = val
+        },
+        // 页码选择器改变
+        handleSizeChange (val) {
+            this.requestPage.limit = val
+            this.requestPage.pageNo = 1
+        },
+        showAndHide (data) {
+            if (data.includes('平行试验') || data.includes('留样再测') || data.includes('比对方案')) {
+                this.show = true
+            } else {
+                this.show = false
+            }
+        },
+        // 计算结果
+        computedResult () {
+            if (this.disabled) {
+                this.$message.warning('导入数据请勿使用计算功能!')
+                return
+            }
+            const hasInvalidData = this.reagentData.some(item =>
+                !item.jiuJieGuo || item.jiuJieGuo <= 0 || !item.xinJieGuo || item.xinJieGuo <= 0
+            )
+
+            if (hasInvalidData || this.reagentData.length === 0) {
+                this.$message.warning('新、旧试剂测得结果必须大于0且不能为空!')
+                return
+            }
+
+            const hasPyOrCz = this.reagentData.some(item =>
+                (item.jiSuanFangShi === '|Y-X|/X(%)' && !item.yunXuPianYi) || (item.jiSuanFangShi === '|Y-X|' && !item.zuiXiaoFanWei)
+            )
+
+            if (hasPyOrCz) {
+                this.$message.warning(`计算方式为|Y-X|/X(%)请填写允许偏倚,计算方式为|Y-X|请填写${this.isHz ? '允许差值' : '限定范围'}`)
+                return
+            }
+            // 预处理函数:统一处理百分比数值
+            const normalizePercent = val => Number(String(val).replace('%', '')) || 0
+
+            // 使用 Map 存储统计信息
+            const projectStats = new Map()
+
+            this.reagentData.forEach(item => {
+                const { jiSuanFangShi, xinJieGuo, jiuJieGuo, zuiXiaoFanWei, jianCeXiangMu } = item
+
+                // 计算差值/偏倚
+                if (jiSuanFangShi === '|Y-X|') {
+                    item.shiJiChaZhi = Math.abs(xinJieGuo - jiuJieGuo)
+                    item.xiangFu = normalizePercent(item.shiJiChaZhi) <= normalizePercent(zuiXiaoFanWei) ? '相符' : '不相符'
+                    item.jieGuo = ''
+                } else {
+                    item.jieGuo = this.deleteAccuracy(Math.abs(xinJieGuo - jiuJieGuo) / jiuJieGuo)
+                    item.xiangFu = normalizePercent(item.jieGuo) <= normalizePercent(item.yunXuPianYi) ? '相符' : '不相符'
+                    item.shiJiChaZhi = ''
+                }
+
+                // 统计符合率
+                const stats = projectStats.get(jianCeXiangMu) || { total: 0, yes: 0 }
+                stats.total++
+                if (item.xiangFu === '相符') stats.yes++
+                projectStats.set(jianCeXiangMu, stats)
+            })
+
+            // 填充符合率标准,保留小数点后两位
+            this.reagentData.forEach(item => {
+                const stats = projectStats.get(item.jianCeXiangMu)
+                item.biaoZhun = this.deleteAccuracy(stats.yes / stats.total)
+                console.log(parseFloat(item.biaoZhun), item.xiangMuFuHeLv)
+                item.jieLun = parseFloat(item.biaoZhun) >= parseFloat(item.xiangMuFuHeLv.replace(/[≥=%]/g, '')) ? '可接受' : '不可接受'
+            })
+        },
+        spanMethod ({ row, column, rowIndex, columnIndex }) {
+            if (columnIndex === 1 || columnIndex === 12 || columnIndex === 13 || columnIndex === 14) {
+                const currentValue = row[column.property]
+                const preRow = this.reagentData[rowIndex - 1]
+                // 上一行这一列的数据
+                const preValue = preRow ? preRow[column.property] : null
+                // 如果当前值和上一行的值相同,则将当前单元格隐藏
+                // 给第0,10,11,12列对数值相同且是同一个'jianCeXiangMu'进行表格合并
+                if (currentValue === preValue && row['jianCeXiangMu'] === preRow['jianCeXiangMu']) {
+                    return { rowspan: 0, colspan: 0 }
+                } else {
+                    let rowspan = 1
+                    // 计算应该合并的行数
+                    for (let i = rowIndex + 1; i < this.reagentData.length; i++) {
+                        const nextRow = this.reagentData[i]
+                        const nextValue = nextRow[column.property]
+                        if (nextValue === currentValue && nextRow['jianCeXiangMu'] === row['jianCeXiangMu']) {
+                            rowspan++
+                        } else {
+                            break
+                        }
+                    }
+                    return { rowspan, colspan: 1 }
+                }
+                // if (rowIndex % rowspan === 0) {
+                //     return {
+                //         rowspan,
+                //         colspan: 1
+                //     }
+                // } else {
+                //     return {
+                //         rowspan: 0,
+                //         colspan: 0
+                //     }
+                // }
+            }
+        },
+        // 去除小数*100精度方法
+        deleteAccuracy (num) {
+            // 是否带小数点
+            if ((num.toString()).includes('.')) {
+                // 保留小数点后面3位
+                const numArry = num.toFixed(3).toString().split('.')
+                // 整数位是否大于0
+                if (numArry[0] > 0) {
+                    return Number(numArry[0] + numArry[1].substring(0, 2) + '.' + numArry[1].substring(2, 3)) + '%'
+                } else {
+                    // 小数位第一位是否大于0
+                    if (numArry[1][0] > 0) {
+                        return Number(numArry[1].substring(0, 2) + '.' + numArry[1].substring(2, 3)) + '%'
+                    } else {
+                        // 小数位第二位是否大于0
+                        if (numArry[1][1] > 0) {
+                            return Number(numArry[1].substring(1, 2) + '.' + numArry[1].substring(2, 3)) + '%'
+                        } else {
+                            return Number(0 + '.' + numArry[1].substring(2, 3)) + '%'
+                        }
+                    }
+                }
+            } else {
+                return num * 100 + '%'
+            }
+        }
+    }
+}
+</script>
+<style lang="scss" scoped>
+.reagentChange{
+    margin-bottom: 20px;
+    .button{
+        display: flex;
+        justify-content: space-between;
+        padding: 0px 0px 0px 15px;
+        background: #f0ffff;
+        .title {
+            color: #999;
+            font-size: 12px;
+            font-weight: bold;
+            margin-bottom: 0;
+        }
+        .el-button {
+            margin: 0;
+        }
+    }
+}
+</style>

+ 1 - 1
src/views/component/reagent/reagentChange.vue

@@ -344,7 +344,7 @@ export default {
             this.requestPage.pageNo = 1
         },
         showAndHide (data) {
-            if (data.includes('平行试验') || data.includes('留样再测') || data.includes('比方案')) {
+            if (data.includes('平行试验') || data.includes('留样再测') || data.includes('比方案')) {
                 this.show = true
             } else {
                 this.show = false

+ 152 - 0
src/views/component/system/logToSql.vue

@@ -0,0 +1,152 @@
+<template>
+    <div>
+        <el-dialog
+            :title="title"
+            :visible.sync="dialogVisible"
+            :close-on-click-modal="false"
+            :close-on-press-escape="false"
+            :show-close="false"
+            append-to-body
+            width="60%"
+            class="dialog json-parse-dialog"
+            top="5vh"
+            @close="closeDialog"
+        >
+            <div class="contain">
+                <div class="item">
+                    <div class="label">以下内容仅供技术人员恢复数据使用</div>
+                    <div class="value">
+                        <el-input
+                            v-model="result"
+                            v-loading="loading"
+                            type="textarea"
+                            :autosize="{ minRows: 10, maxRows: 24}"
+                            placeholder=""
+                            disabled
+                        />
+                    </div>
+                </div>
+            </div>
+            <div slot="footer" class="el-dialog--center">
+                <ibps-toolbar :actions="toolbars" @action-event="handleActionEvent" />
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import { dataToSql } from '@/api/platform/system/news'
+export default {
+    props: {
+        visible: {
+            type: Boolean,
+            default: false
+        },
+        params: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        }
+    },
+    data () {
+        return {
+            title: 'JSON解析结果',
+            dialogVisible: true,
+            loading: false,
+            result: '',
+            toolbars: [
+                { key: 'copy', icon: 'ibps-icon-copy', label: '复制', type: 'primary', hidden: () => !this.result || this.loading },
+                { key: 'cancel', icon: 'el-icon-close', label: '关闭', type: 'danger' }
+            ]
+        }
+    },
+    watch: {
+        visible: {
+            handler (newVal) {
+                console.log(newVal)
+                this.dialogVisible = newVal
+                if (newVal) {
+                    this.loadData()
+                }
+            },
+            immediate: true
+        }
+    },
+    methods: {
+        async loadData () {
+            try {
+                this.loading = true
+                const { logId } = this.params
+                const response = await dataToSql({ logId })
+                this.result = response?.data?.sql || ''
+            } catch (error) {
+                console.error('数据解析失败:', error)
+                this.$message.error('数据解析失败')
+                this.result = '数据解析失败,请重试'
+            } finally {
+                this.loading = false
+            }
+        },
+        handleActionEvent ({ key }) {
+            switch (key) {
+                case 'copy':
+                    this.handleCopy(this.result)
+                    break
+                case 'cancel':
+                    this.closeDialog()
+                    break
+                default:
+                    break
+            }
+        },
+        handleCopy (text) {
+            if (navigator.clipboard) {
+                navigator.clipboard.writeText(text).then(() => {
+                    this.$message.success('复制成功')
+                }).catch(() => this.fallbackCopy(text))
+            } else {
+                this.fallbackCopy(text)
+            }
+        },
+        fallbackCopy (text) {
+            const textarea = document.createElement('textarea')
+            textarea.value = text
+            textarea.style.position = 'fixed'
+            document.body.appendChild(textarea)
+            textarea.select()
+            try {
+                document.execCommand('copy')
+                this.$message.success('复制成功')
+            } catch (err) {
+                this.$message.warning('复制失败,请手动选择内容复制!')
+            } finally {
+                document.body.removeChild(textarea)
+            }
+        },
+        closeDialog () {
+            this.dialogVisible = false
+        }
+    }
+
+}
+</script>
+
+<style lang="scss" scoped>
+.json-parse-dialog {
+    .contain{
+        .item {
+            padding: 15px;
+            .label {
+                font-size: 16px;
+                font-weight: bold;
+                margin-bottom: 10px;
+            }
+            .value {
+                font-size: 16px;
+                color: #666;
+            }
+        }
+    }
+}
+</style>

+ 14 - 2
src/views/component/trainingManage/trainingStatic.vue

@@ -290,11 +290,23 @@ export default {
                     }
                 }]
             }
-
+            // 更新人员培训记录的培训人
+            const params2 = {
+                tableName: 't_xygpx',
+                updList: [{
+                    where: {
+                        pei_xun_ming_chen: row.id_
+                    },
+                    param: {
+                        parent_id_: buQianRen === '' ? this.params.peixunrenyuan : buQianRen + ',' + this.params.peixunrenyuan
+                    }
+                }]
+            }
             // 合并请求
             Promise.all([
                 this.$common.request('add', addParams),
-                this.$common.request('update', params)
+                this.$common.request('update', params),
+                this.$common.request('update', params2)
             ]).then(async ([addRes, updateRes]) => {
                 console.log('补签签到数据成功', addRes)
                 console.log('更新补签考试人员', updateRes)

+ 3 - 0
src/views/platform/bpmn/bpmInstHis/list.vue

@@ -717,6 +717,7 @@ export default {
                             this.$common.request('delete', deleteParams2)
                         })
                         this.$message.success('删除成功!')
+                        this.$refs['crud']?.clearSelection()
                         this.search()
                     })
                 }).catch(() => {
@@ -727,6 +728,8 @@ export default {
         handleNodeClick (typeId, typeName) {
             this.tableTitle = typeName.name
             this.typeId = typeId
+            // 切换分类清除选中数据
+            this.$refs['crud']?.clearSelection()
             this.templateData = this.reportAll.template.find(i => i.fen_lei_id_ === typeId) || {}
             if (!this.templateData.templateid_) {
                 this.templateShow = false

+ 18 - 6
src/views/platform/examination/exam/list.vue

@@ -73,6 +73,7 @@ import { examTypeOptions, statusOption, basicColumn, infoColumn, resultColumn }
 import ActionUtils from '@/utils/action'
 import FixHeight from '@/mixins/height'
 import { max, min, mean, sum, maxBy, minBy, meanBy, round, keyBy, mapValues } from 'lodash'
+import { removeFormData } from '@/api/platform/data/dataTemplate'
 
 const sortField = {
     CREATE_TIME_: 'ex.chuang_jian_shi_j',
@@ -624,7 +625,9 @@ export default {
                     end_time_: limitDate !== '不限' ? limitDate.slice(0, 10) : now,
                     emergency_state_: '2',
                     user_id_: i,
-                    user_name_: this.transformUser(i)
+                    user_name_: this.transformUser(i),
+                    data_source_id_: examId,
+                    data_info_: 't_exams'
                 }))
                 this.$common.request('add', {
                     tableName: 'ibps_party_user_calendar',
@@ -715,20 +718,29 @@ export default {
             if (!ids || !ids.length) {
                 return this.$message.warning('请选择要删除的考试!')
             }
-            this.$confirm('数据一旦删除无法恢复,确定要删除选中的考试吗?', '提示', {
+            this.$confirm('将删除所选考试及已产生的试卷数据,数据删除后无法恢复,确定要继续吗?', '提示', {
                 confirmButtonText: '确认',
                 cancelButtonText: '取消',
                 type: 'warning',
                 showClose: false,
                 closeOnClickModal: false
             }).then(() => {
-                this.$common.request('delete', {
-                    tableName: 't_exams',
-                    paramWhere: { id_: ids.join(',') }
+                removeFormData({
+                    formKey: 'examForDelete',
+                    ids: ids.join(',')
                 }).then(() => {
                     ActionUtils.removeSuccessMessage()
                     this.search()
-                })
+                }).catch(() => {})
+
+                // // 自定义删除方法,弃用,无法联动删除子表数据及考试对应日程数据
+                // this.$common.request('delete', {
+                //     tableName: 't_exams',
+                //     paramWhere: { id_: ids.join(',') }
+                // }).then(() => {
+                //     ActionUtils.removeSuccessMessage()
+                //     this.search()
+                // })
             })
         },
         transformUser (userId) {

+ 30 - 30
src/views/platform/risk/riskDetail.vue

@@ -126,7 +126,7 @@
                                 <span>{{ row.feng_xian_lai_yua==='2'?'新增':'风险库' }}</span>
                             </template>
                         </el-table-column>
-                        <el-table-column
+                        <!-- <el-table-column
                             prop="yao_su_tiao_kuan_"
                             label="要素条款"
                             width="120"
@@ -134,10 +134,10 @@
                             <template slot-scope="{row}">
                                 <el-input v-model="row.yao_su_tiao_kuan_" type="textarea" :rows="2" size="mini" :disabled="readonly" />
                             </template>
-                        </el-table-column>
+                        </el-table-column> -->
                         <el-table-column
                             prop="gong_zuo_huan_jie"
-                            label="工作环节"
+                            label="工作流程和质量管理活动"
                             width="150"
                         >
                             <template slot-scope="{row}">
@@ -155,7 +155,7 @@
                         </el-table-column> -->
                         <el-table-column
                             prop="feng_xian_miao_sh"
-                            label="风险描述"
+                            label="风险描述(风险事件)"
                             width="150"
                         >
                             <template slot-scope="{row}">
@@ -163,23 +163,14 @@
                             </template>
                         </el-table-column>
                         <el-table-column
-                            prop="xian_xing_kong_zh"
-                            label="现行控制方法"
-                            width="150"
-                        >
-                            <template slot-scope="{row}">
-                                <el-input v-model="row.xian_xing_kong_zh" type="textarea" :rows="2" size="mini" :disabled="readonly" />
-                            </template>
-                        </el-table-column>
-                        <el-table-column
-                            prop="yan_zhong_cheng_d"
-                            label="严重程度"
+                            prop="fa_sheng_pin_du_"
+                            label="发生概率"
                             width="100"
                         >
                             <template slot-scope="{row}">
-                                <el-select v-model="row.yan_zhong_cheng_d" placeholder="请选择" :disabled="readonly" size="mini" @change="culRate(row)">
+                                <el-select v-model="row.fa_sheng_pin_du_" placeholder="请选择" :disabled="readonly" size="mini" @change="culRate(row)">
                                     <el-option
-                                        v-for="item in yan_zhong_cheng_d_List"
+                                        v-for="item in fa_sheng_pin_du_List"
                                         :key="item"
                                         :label="item"
                                         :value="item"
@@ -188,26 +179,25 @@
                             </template>
                         </el-table-column>
                         <el-table-column
-                            prop="fa_sheng_pin_du_"
-                            label="发生频度"
+                            prop="yan_zhong_cheng_d"
+                            label="严重程度"
                             width="100"
                         >
                             <template slot-scope="{row}">
-                                <el-select v-model="row.fa_sheng_pin_du_" placeholder="请选择" :disabled="readonly" size="mini" @change="culRate(row)">
+                                <el-select v-model="row.yan_zhong_cheng_d" placeholder="请选择" :disabled="readonly" size="mini" @change="culRate(row)">
                                     <el-option
-                                        v-for="item in fa_sheng_pin_du_List"
+                                        v-for="item in yan_zhong_cheng_d_List"
                                         :key="item"
                                         :label="item"
                                         :value="item"
                                     />
                                 </el-select>
                             </template>
-
                         </el-table-column>
                         <el-table-column
                             v-if="muban==='2'"
                             prop="ke_jian_ce_du_"
-                            label="可检测度"
+                            label="可检测度(FMEA法)"
                             width="100"
                         >
                             <template slot-scope="{row}">
@@ -224,7 +214,7 @@
                         </el-table-column>
                         <el-table-column
                             prop="feng_xian_zhi_shu"
-                            label="风险系数"
+                            label="风险得分(FMEA法)"
                             width="70"
                         />
                         <el-table-column
@@ -232,15 +222,25 @@
                             label="风险等级"
                             width="100"
                         />
+                        <el-table-column
+                            prop="xian_xing_kong_zh"
+                            label="现行控制措施"
+                            width="150"
+                        >
+                            <template slot-scope="{row}">
+                                <el-input v-model="row.xian_xing_kong_zh" type="textarea" :rows="2" size="mini" :disabled="readonly" />
+                            </template>
+                        </el-table-column>
                         <el-table-column
                             prop="feng_xian_ying_du"
-                            label="风险应对"
+                            label="残余风险(是否接受)"
                             width="120"
                         >
+                        <!-- 选择风险不接受,开风险控制评价表流程 -->
                             <template slot-scope="{row}">
                                 <el-select v-model="row.feng_xian_ying_du" placeholder="请选择" :disabled="readonly" size="mini">
                                     <el-option
-                                        v-for="item in ['风险降低','风险接受','风险回避']"
+                                        v-for="item in ['风险接受','风险不接受']"
                                         :key="item"
                                         :label="item"
                                         :value="item"
@@ -701,8 +701,8 @@ export default {
                                 }
                             }
                         }
-
-                        this.$set(row, 'feng_xian_ying_du', (!row.feng_xian_ying_du && degree === '低') ? '风险接受' : '风险降低')
+console.log('row.feng_xian_ying_du', row.feng_xian_ying_du, degree)
+                        this.$set(row, 'feng_xian_ying_du', (!row.feng_xian_ying_du && degree === '低') ? '风险接受' : '风险不接受')
                         row.feng_xian_zhi_shu = rate + ''
                         row.feng_xian_deng_ji = degree
                     }
@@ -742,7 +742,7 @@ export default {
                             }
                         }
 
-                        this.$set(row, 'feng_xian_ying_du', (!row.feng_xian_ying_du && (degree === '可忽略的' || degree === '可接受的')) ? '风险接受' : '风险降低')
+                        this.$set(row, 'feng_xian_ying_du', (!row.feng_xian_ying_du && (degree === '可忽略的' || degree === '可接受的')) ? '风险接受' : '风险不接受')
                         row.feng_xian_zhi_shu = rate + ''
                         row.feng_xian_deng_ji = degree
                     }
@@ -776,7 +776,7 @@ export default {
                             }
                         }
 
-                        this.$set(row, 'feng_xian_ying_du', (!row.feng_xian_ying_du && (degree === '低风险')) ? '风险接受' : '风险降低')
+                        this.$set(row, 'feng_xian_ying_du', (!row.feng_xian_ying_du && (degree === '低风险')) ? '风险接受' : '风险不接受')
                         row.feng_xian_zhi_shu = rate + ''
                         row.feng_xian_deng_ji = degree
                     }

+ 5 - 3
src/views/platform/risk/riskV2.vue

@@ -405,8 +405,7 @@ export default {
 
     async mounted () {
         const culWays = await getSetting('risk', 'culWays')
-        if (culWays) {
-            console.debug(culWays)
+        if (this.$utils.isNotEmpty(culWays)) {
             this.culWays = culWays
         }
         this.init()
@@ -881,11 +880,14 @@ export default {
                 }
                 await this.showAlert()
             } else {
+                const { positions } = this.$store.getters.userInfo
+                // 默认编制部门是主部门,没有主部门默认第一个部门
+                const mainPost = positions.find(item => item.isMainPost === 'Y')?.id || positions[0].id
                 this.readonly = false
                 this.infoFxssbData.di_dian_ = this.level
                 this.infoFxssbData.ji_hua_bian_hao_ = await this.getNextAlias('fxjhlsh')
                 this.infoFxssbData.nian_du_ = dayjs().format('YYYY')
-                this.infoFxssbData.bian_zhi_bu_men_ = this.position
+                this.infoFxssbData.bian_zhi_bu_men_ = mainPost
                 this.infoFxssbData.bian_zhi_ren_ = this.userId
                 this.infoFxssbData.bian_zhi_shi_jian = dayjs().format('YYYY-MM-DD HH:mm:ss')
                 this.infoFxssbData.zu_chang_id_ = this.userId

+ 38 - 23
src/views/platform/system/tools/convertByAes.vue

@@ -42,7 +42,7 @@
                         size="small"
                         icon="ibps-icon-copy"
                         @click="handleCopy"
-                    >复制明文SQL</el-button>
+                    >复制明文</el-button>
                 </div>
                 <div class="item">
                     <div class="label">密文</div>
@@ -55,6 +55,17 @@
                         />
                     </div>
                 </div>
+                <!-- <div class="item">
+                    <div class="label">ivBase64</div>
+                    <div class="value">
+                        <el-input
+                            v-model="ivBase64"
+                            type="textarea"
+                            :rows="1"
+                            placeholder="请输入ivBase64"
+                        />
+                    </div>
+                </div> -->
             </div>
         </div>
     </el-dialog>
@@ -72,6 +83,7 @@ export default {
         return {
             dialogVisible: this.visible,
             plaintext: '',
+            ivBase64: '',
             ciphertext: ''
         }
     },
@@ -99,9 +111,12 @@ export default {
             this.ciphertext = this.$common.encryptByAes(this.plaintext)
         },
         handleDecrypt () {
-            if (!this.ciphertext) {
-                return this.$message.warning('请输入密文!')
+            if (!this.ciphertext || typeof this.ciphertext !== 'string') {
+                return this.$message.warning('无效的密文输入!')
             }
+            // if (!this.ivBase64) {
+            //     return this.$message.warning('请输入ivBase64!')
+            // }
             const temp = this.$common.decryptByAes(this.ciphertext)
             if (this.$utils.isEmpty(temp)) {
                 return this.$message.error('密文无效,无法解密!')
@@ -109,28 +124,28 @@ export default {
             this.plaintext = temp
         },
         handleCopy () {
-            if (!this.plaintext) {
-                return this.$message.warning('明文为空!')
+            const text = this.plaintext
+            if (navigator.clipboard) {
+                navigator.clipboard.writeText(text).then(() => {
+                    this.$message.success('明文已复制到剪贴板!')
+                }).catch(() => this.fallbackCopy(text))
+            } else {
+                this.fallbackCopy(text)
             }
+        },
+        fallbackCopy (text) {
+            const textarea = document.createElement('textarea')
+            textarea.value = text
+            textarea.style.position = 'fixed'
+            document.body.appendChild(textarea)
+            textarea.select()
             try {
-                const temp = JSON.parse(this.plaintext)
-                const hasSql = temp.hasOwnProperty('sql')
-                // 明文是 JSON 格式
-                navigator.clipboard.writeText(temp.sql || this.plaintext).then(() => {
-                    const msg = hasSql ? '明文SQL已复制到剪贴板!' : '明文中不含SQL,已复制所有内容到剪贴板!'
-                    this.$message.success(msg)
-                }).catch(error => {
-                    this.$message.error('复制失败!')
-                    console.log(error)
-                })
-            } catch (e) {
-                // 明文不是 JSON 格式
-                navigator.clipboard.writeText(this.plaintext).then(() => {
-                    this.$message.success('明文内容已复制到剪贴板!')
-                }).catch(error => {
-                    this.$message.error('复制失败!')
-                    console.log(error)
-                })
+                document.execCommand('copy')
+                this.$message.success('明文已复制到剪贴板!')
+            } catch (err) {
+                this.$message.warning('复制失败,请手动选择内容复制!')
+            } finally {
+                document.body.removeChild(textarea)
             }
         },
         closeDialog () {

+ 1 - 4
src/views/system/fasc/facilityEnvConfig.vue

@@ -222,8 +222,6 @@
 <script>
 import { getSetting } from '@/utils/query'
 import ibpsUserSelector from '@/business/platform/org/selector'
-import xlsx from 'xlsx'
-import fs from 'file-saver'
 import FecDialog from './fecDialog.vue'
 import FacilityData from '@/views/component/facility/facilityData.vue'
 import DefaultSettingDialog from './defaultSettingDialog.vue'
@@ -469,8 +467,7 @@ export default {
     },
     async mounted () {
         const config = await getSetting('facilityEnv', 'typeList')
-        if (config) {
-            console.debug(config)
+        if (this.$utils.isNotEmpty(config)) {
             this.config = config
         }
         this.init()

+ 1 - 0
src/views/system/homepage/components/mySchedule.vue

@@ -15,6 +15,7 @@
         <v-full-calendar
             ref="calendar"
             :options="scheduleConfig"
+            :hide-other-month-days="true"
             :style="{height: '100%', width: '100%'}"
         />
     </el-dialog>