Forráskód Böngészése

试验检测表单

iZaiZaiA 3 éve
szülő
commit
a931f3cd70

+ 1 - 1
src/global/components/hc-tooltip/index.vue

@@ -6,7 +6,7 @@
 
 <script setup>
 import {ref,watch,onMounted} from "vue";
-import {useAppStore} from "~src/store/index";
+import {useAppStore} from "~src/store";
 const useAppState = useAppStore()
 
 //参数

+ 6 - 0
src/router/modules/base.js

@@ -246,6 +246,12 @@ export default [
                 name: 'tentative-detect-test',
                 meta: {title: '试验检测'},
                 component: () => import('~src/views/tentative/detect/test.vue')
+            },
+            {
+                path: '/tentative/detect/test-form',
+                name: 'tentative-detect-test-form',
+                meta: {title: '试验检测表单'},
+                component: () => import('~src/views/tentative/detect/test-form.vue')
             }
         ],
     },

+ 1 - 0
src/router/modules/token.js

@@ -10,4 +10,5 @@ export default [
     'order-service',
     'user-index',
     'test-index',
+    'tentative-detect-test-form',
 ]

+ 0 - 0
src/styles/tentative/detect/test-form.scss


+ 131 - 0
src/views/tentative/detect/components/HcUpload.vue

@@ -0,0 +1,131 @@
+<template>
+    <el-upload class="hc-upload-border" drag :action="action" :headers="getTokenHeader()" :data="uploadData" :accept="accept" :file-list="fileListData" multiple :disabled="uploadDisabled"
+               :on-preview="uploadPreview" :before-remove="delUploadData" :on-success="uploadSuccess" :on-exceed="uploadExceed" :on-error="uploadError" :before-upload="beforeUpload"
+               :on-progress="uploadprogress" :on-remove="uploadRemove">
+        <div class="hc-upload-loading" v-loading="uploadDisabled" :element-loading-text="loadingText">
+            <HcIcon name="backup" ui="text-5xl mt-4"/>
+            <div class="el-upload__text">拖动文件到这里 或 <em>点击这里选择文件</em> 并上传</div>
+        </div>
+        <template #tip>
+            <div class="el-upload__tip" style="font-size: 14px;">允许格式:jpg/png/pdf/excel/word, 文件大小 小于 60MB</div>
+        </template>
+    </el-upload>
+</template>
+
+<script setup>
+import {ref,watch,onMounted} from "vue";
+import {getTokenHeader} from '~src/api/request/header';
+import wbsApi from "~api/data-fill/wbs"
+import {isSize} from "vue-utils-plus"
+const props = defineProps({
+    fileList: {
+        type: Array,
+        default: () => ([])
+    },
+    datas: {
+        type: Object,
+        default: () => ({})
+    },
+})
+
+//变量
+const uploadData = ref(props.datas)
+const fileListData = ref(props.fileList);
+const action = '/api/blade-manager/exceltab/add-buss-file';
+const accept = 'image/png,image/jpg,image/jpeg,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/pdf,.doc,.docx,application/msword';
+const uploadDisabled = ref(false)
+
+//监听
+watch(() => [
+    props.fileList,
+    props.datas,
+], ([fileList, datas]) => {
+    uploadData.value = datas
+    fileListData.value = fileList
+})
+
+//渲染完成
+onMounted(()=> {
+    beforeFileNum.value = 0
+    finishFileNum.value = 0
+    errorFileNum.value = 0
+})
+
+//事件
+const emit = defineEmits(['change'])
+
+//上传前
+const beforeFileNum = ref(0)
+const beforeUpload = async (file) => {
+    if (isSize(file?.size,60)) {
+        beforeFileNum.value ++;
+        return true;
+    } else {
+        window?.$message?.warning('文件大小, 不能过60M!');
+        return false;
+    }
+}
+
+//超出限制时
+const uploadExceed = () => {
+    window?.$message?.warning('请上传 jpg/png/pdf/excel/word 的文件,文件大小 不超过60M');
+}
+
+//上传中
+const loadingText = ref('上传中...')
+const uploadprogress = () => {
+    loadingText.value = '上传中...'
+    uploadDisabled.value = true
+}
+
+//上传完成
+const finishFileNum = ref(0)
+const uploadSuccess = () => {
+    finishFileNum.value ++;
+    if (beforeFileNum.value === finishFileNum.value) {
+        uploadDisabled.value = false
+        emit('change', {type: 'success'})
+    }
+}
+
+//上传失败
+const errorFileNum = ref(0)
+const uploadError = () => {
+    errorFileNum.value ++;
+    window?.$message?.error('上传失败');
+    const num = finishFileNum.value + errorFileNum.value;
+    if (beforeFileNum.value === num) {
+        uploadDisabled.value = false
+        emit('change', {type: 'success'})
+    }
+}
+
+//预览
+const uploadPreview = ({url}) => {
+    if (url) {
+        window.open(url, '_blank')
+    }
+}
+
+//删除文件
+const delUploadData = async ({id}) => {
+    loadingText.value = '删除中...'
+    uploadDisabled.value = true
+    const {error, code} = await wbsApi.removeBussFile({
+        ids: id
+    })
+    uploadDisabled.value = false
+    if (!error && code === 200) {
+        window?.$message?.success('删除成功')
+        return true
+    } else {
+        return false
+    }
+}
+
+const uploadRemove = () => {
+    if(fileListData.value.length <= 0) {
+        emit('change', {type: 'del'})
+    }
+}
+</script>

+ 866 - 0
src/views/tentative/detect/components/ListItem.vue

@@ -0,0 +1,866 @@
+<template>
+    <div class="data-fill-list-box">
+        <el-collapse v-model="ActiveKey" accordion @change="CollapseChange">
+            <template v-for="(item,index) in listDatas" :key="item?.pkeyId">
+                <el-collapse-item :name="`item-${index}-${item?.pkeyId}`" :disabled="item['isBussShow'] === 2" :id="`item-${index}-${item?.pkeyId}`">
+                    <template #title>
+                        <div class="hc-collapse-item-header">
+                            <div class="text-lg truncate item-title">{{item.nodeName}}</div>
+                            <div class="hc-extra-text-box">
+                                <HcTooltip keys="wbs_del_table" v-if="item['isCopeTab'] === 2">
+                                    <el-button type="danger" plain :disabled="item['isBussShow'] === 2" @click.stop="delClick(item,index)">删除本表</el-button>
+                                </HcTooltip>
+                                <HcTooltip keys="wbs_copy_table">
+                                    <el-button type="primary" plain :disabled="item['isBussShow'] === 2" @click.stop="copyClick(item,index)">复制本表</el-button>
+                                </HcTooltip>
+                                <HcTooltip keys="wbs_hide_table">
+                                    <el-button type="primary" plain @click.stop="hideClick(item,index)">
+                                        <template v-if="item['isBussShow'] === 1">隐藏本表</template>
+                                        <template v-else>显示本表</template>
+                                    </el-button>
+                                </HcTooltip>
+                                <HcTooltip keys="wbs_preview_table">
+                                    <el-button type="info" plain disabled v-if="item['isBussShow'] === 2 || item['isTabPdf'] === 1">预览</el-button>
+                                    <el-button type="primary" plain @click.stop="previewClick(item,index)" v-else>预览</el-button>
+                                </HcTooltip>
+                                <HcTooltip keys="wbs_upload_table">
+                                    <el-button :type="item['tabFileType'] === 2?'success':'primary'" plain :disabled="item['isBussShow'] === 2" @click.stop="uploadClick(item,index)">
+                                        <template v-if="item['tabFileType'] === 2">已上传</template>
+                                        <template v-else>上传</template>
+                                    </el-button>
+                                </HcTooltip>
+                            </div>
+                        </div>
+                    </template>
+                    <div class="data-fill-list-item-content">
+                        <div class="data-fill-table-form-box">
+                            <div class="hc-excel-table-form-view" :id="`table-form-${item?.pkeyId}`"/>
+                            <div class="hc-no-table-form" v-if="item?.isTableForm === false">
+                                <div class="table-form-no">
+                                    <img :src="notableform" alt=""/>
+                                    <div class="desc">暂无表单数据</div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="data-fill-table-tip-box">
+                            <div class="text-orange tip-title">
+                                <HcIcon name="error" fill ui="text-2xl"/>
+                                <span class="ml-1">提示</span>
+                            </div>
+                            <div class="text-gray-400 tip-item">1、灰色框代表可通过系统识别计算,公式自动引用,可通过公式计算少量数据,(表头数据及简单),也可只填写白色框数据</div>
+                            <div class="text-gray-400 tip-item">2、系统支持键盘中,shift + tab键向上一个填报框切换,tab向下一个填报框切换。暂不支持上下按键切换输入框</div>
+                            <div class="table-tip-foot">
+                                <div class="tip-left-btn">
+                                    <HcTooltip keys="wbs_import_table">
+                                        <div class="text-gray-400 dow-text">
+                                            <HcIcon name="publish" ui="text-lg"/>
+                                            <span class="ml-1">导入列表数据</span>
+                                        </div>
+                                    </HcTooltip>
+                                    <HcTooltip keys="wbs_download_table">
+                                        <div class="text-main dow-text">
+                                            <HcIcon name="file_download" ui="text-lg"/>
+                                            <span class="ml-1">下载导入模板</span>
+                                        </div>
+                                    </HcTooltip>
+                                </div>
+                                <div class="tip-right-btn">
+                                    <HcTooltip keys="wbs_save_table">
+                                        <el-button type="primary" hc-btn :disabled="item?.isTableForm === false" :loading="tableFormSaveLoading" @click="tableFormSaveClick(item,index)">
+                                            <HcIcon name="save"/>
+                                            <span>保存</span>
+                                        </el-button>
+                                    </HcTooltip>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </el-collapse-item>
+            </template>
+        </el-collapse>
+    </div>
+
+    <!--右键菜单-->
+    <HcContextMenu ref="contextMenuRef" :datas="tableFormMenu" @item-click="handleMenuSelect"/>
+
+    <!--上传文件-->
+    <HcDialog :show="uploadModal" title="上传文件" widths="38rem" :footer="false" @close="uploadModal = false">
+        <HcUpload :fileList="fileListData" :datas="uploadData" @change='uploadChange'/>
+    </HcDialog>
+
+    <!--插入设计值/频率-->
+    <HcDialog :show="IDVFModal" title="插入设计值/频率" widths="600px" saveText="确认插入" @close="IDVFModal = false" @save="IDVFModalSaveClick">
+        <el-alert title="填写完设计值和频率,系统自动计算实测值" type="warning" :closable="false"/>
+        <el-form ref="formIDVFRef" :model="formIDVFModel" label-width="auto" size="large">
+            <div class="form-item-div text-center mb-3">
+                <el-radio-group size="large" v-model="formIDVFModel.type">
+                    <el-radio :label="1">公路工程</el-radio>
+                    <el-radio :label="2" class="ml-4">水利水电</el-radio>
+                </el-radio-group>
+            </div>
+            <el-form-item label="设计值">
+                <el-input v-model="formIDVFModel.design" placeholder="请输入设计值"/>
+            </el-form-item>
+            <el-form-item label="频率" v-if="formIDVFModel.type === 1">
+                <el-input v-model="formIDVFModel.size" placeholder="请输入频率"/>
+            </el-form-item>
+            <el-form-item label="容量" v-if="formIDVFModel.type === 2">
+                <el-input v-model="formIDVFModel.capacity" placeholder="请输入容量"/>
+            </el-form-item>
+            <el-form-item label="合格点数">
+                <el-input v-model="formIDVFModel.fail" placeholder="请填写合格点数(不填写则默认全部合格)"/>
+            </el-form-item>
+        </el-form>
+    </HcDialog>
+
+    <!--插入特殊字符-->
+    <HcDialog :show="specialModal" title="插入特殊字符" widths="600px" saveText="确认插入" @close="specialModal = false" @save="specialNodeClick">
+        <el-form ref="specialFormRef" :model="specialFormModel" :rules="specialFormRules" label-width="0px" size="large" class="mb-6">
+            <el-form-item prop="val" class="special-form-item">
+                <el-input v-model="specialFormModel.val" ref="specialRef" id="specialId" placeholder="请选择特殊字符代码" clearable @blur="specialInputBlur"/>
+            </el-form-item>
+        </el-form>
+        <el-row :gutter="20" style="margin: -10px;">
+            <el-col :span="3" style="padding: 10px;" v-for="item in specialCharacters">
+                <div class="special-box" @click="specialClick">
+                    <span class="font-EUDC" :title="`字符代码(C):${item !== 'K̅'?item.slice(2,7):'K̅'}`" v-html="item"/>
+                </div>
+            </el-col>
+        </el-row>
+    </HcDialog>
+
+    <!--关联试验数据-->
+    <HcDialog :show="CTDModal" title="关联试验数据" widths="850px" saveText="确认关联" @close="CTDModal = false" @save="CTDModal = false">
+        开发中...
+    </HcDialog>
+</template>
+
+<script setup>
+import {ref,watch,nextTick} from "vue";
+import notableform from '~src/assets/view/notableform.svg';
+import HTableForm from "~src/plugins/HTableForm"
+import wbsApi from "~api/data-fill/wbs"
+import HcUpload from "./HcUpload.vue"
+import {utilsText, isType, formValidate, deepClone} from "vue-utils-plus"
+
+//初始
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => ([])
+    },
+    classify: {
+        type: [String,Number],
+        default: ''
+    },
+    status: {
+        type: [String,Number],
+        default: ''
+    },
+    primaryKeyId: {
+        type: [String,Number],
+        default: ''
+    },
+    contractId: {
+        type: [String,Number],
+        default: ''
+    },
+})
+const {isString, getObjNullValue, getArrValue} = isType()
+const {setPosInsert, setPosRange} = utilsText()
+const listDatas = ref(props.datas)
+const classify = ref(props.classify)
+const isStatus = ref(props.status)
+const isPrimaryKeyId = ref(props.primaryKeyId)
+const contractId = ref(props.contractId)
+
+//监听
+watch(() => [
+    props.datas,
+    props.classify,
+    props.primaryKeyId,
+    props.contractId,
+], ([datas, classifyVal, primaryKeyId, cid]) => {
+    listDatas.value = datas
+    classify.value = classifyVal
+    isPrimaryKeyId.value = primaryKeyId
+    contractId.value = cid
+    setFormDataNum(datas)
+})
+
+//监听
+watch(() => [
+    props.status
+], ([val]) => {
+    //1 未填报,2待上报,3已上报
+    isStatus.value = val
+})
+
+//渲染完成
+nextTick(() => {
+    setFormDataNum(props.datas)
+})
+
+//获取表单初始数据
+const getFormDataInit = (item, pkeyId) => {
+    return {
+        projectId: item?.projectId,
+        contractId: item?.contractId,
+        classify: classify.value,
+        pkeyId: pkeyId ? pkeyId + '' : '',
+        nodeId: isPrimaryKeyId.value
+    }
+}
+
+//设置表单对象的数量
+const formData = ref([])
+const setFormDataNum = (datas) => {
+    ActiveKey.value = ''
+    let newArr = [];
+    for (let i = 0; i < datas.length; i++) {
+        newArr.push({
+            ...getFormDataInit(datas[i], datas[i].pkeyId),
+            isCollapseLoad: false,
+        })
+    }
+    formData.value = newArr
+}
+
+//展开事件
+const ActiveKey = ref('')
+const formKeyIds = ref('')
+const CollapseChange = async (name) => {
+    ActiveKey.value = name
+    const names = name ? name.split('-') : []
+    if (names.length > 0) {
+        getOffsetTop(name)
+        const index = names[1]
+        const item = listDatas.value[index]
+        formKeyIds.value = item.pkeyId ? item.pkeyId + '' : ''
+        if (!item.isTableFormRender) {
+            //获取已填写的数据
+            await getBussDataInfo(item,item.pkeyId, index)
+            //渲染表单
+            await getExcelHtml(item,index)
+        }
+    } else {
+        getOffsetTop()
+        formKeyIds.value = ''
+    }
+}
+
+//获取模板标签数据
+const formRegExpJson = ref({})
+const getExcelHtml = async (item,index) => {
+    const pkeyIds = item.pkeyId ? item.pkeyId + '' : ''
+    if (pkeyIds) {
+        const {error, code, data} = await wbsApi.getExcelHtml({pkeyId: pkeyIds}, false)
+        const resData = isString(data) ? data || '' : ''
+        if (!error && code === 200 && resData) {
+            item.isTableForm = true
+            //渲染表单
+            HTableForm.createForm({
+                template: resData,
+                tableForm: formData.value[index],
+                appId: `#table-form-${pkeyIds}`,
+                onRight: (event, KeyName) => {
+                    onRightClick(event, KeyName, index)
+                },
+                //表单正则效验
+                onBlur: (event, key, reg, val, msg) => {
+                    setTableFormBlurReg(pkeyIds, event, key, reg, val, msg, item, index)
+                }
+            })
+            item.isTableFormRender = true
+            item.isRenderTableForm = true
+        } else {
+            item.isTableForm = false
+            item.isRenderTableForm = true
+            window?.$message?.warning('暂无表单')
+        }
+    } else {
+        item.isTableForm = false
+        item.isRenderTableForm = false
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//正则效验
+const setTableFormBlurReg = (pkeyId, event, key, reg, val, msg, item, index) => {
+    const dom = document.getElementById(key)?.parentElement ?? ''
+    if (dom) {
+        if (val && reg) {
+            let regx = new RegExp(reg);
+            let state = regx.test(val);
+            if (state) {
+                delete formRegExpJson.value[pkeyId]
+                dom.style = ''
+            } else {
+                formRegExpJson.value[pkeyId] = {key, reg, val, msg, state, nodeName: item.nodeName, itemId: `item-${index}-${item?.pkeyId}`}
+                dom.style = '--el-input-border-color: #fe0000; box-shadow: 0 0 0 2px #fe0000 inset;'
+                window?.$message?.warning(msg)
+            }
+        } else {
+            delete formRegExpJson.value[pkeyId]
+            dom.style = ''
+        }
+    }
+}
+
+//获取已填写的数据
+const getBussDataInfo = async (item, pkeyId, index) => {
+    const pkeyIds = pkeyId ? pkeyId + '' : ''
+    if (pkeyIds) {
+        const {error, code, data} = await wbsApi.getBussDataInfo({
+            pkeyId: pkeyIds
+        }, false)
+        const resData = getObjNullValue(data)
+        if (!error && code === 200 && resData) {
+            HTableForm.setPickerKey(resData)
+            const InitObj = getFormDataInit(item, pkeyId) //有数据,关联数据
+            formData.value[index] = {...resData, ...InitObj, isCollapseLoad: true}
+        } else {
+            formData.value[index] = {...getFormDataInit(item, pkeyId), isCollapseLoad: true}
+        }
+    } else {
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//单个保存
+const tableFormSaveLoading = ref(false)
+const tableFormSaveClick = async (item,index) => {
+    if (isStatus.value !== '3') {
+        const res = await saveExcelBussData(item,index)
+        if (res) {
+            await getBussPdfInfo(item)
+            renewData()
+        }
+    } else {
+        window?.$message?.warning('已上报的资料,不允许保存。')
+    }
+}
+
+//保存表单数据
+const saveExcelBussData = async (item, index, showTip = true) => {
+    if (!getObjNullValue(formRegExpJson.value)) {
+        tableFormSaveLoading.value = true
+        const InitObj = getFormDataInit(item, item.pkeyId)
+        const {error, code, data} = await wbsApi.saveExcelBussData({
+            ...formData.value[index],
+            ...InitObj
+        })
+        //处理数据
+        tableFormSaveLoading.value = false
+        if (!error && code === 200) {
+            if(showTip) window?.$message?.success('保存成功')
+            return true
+        } else {
+            return false
+        }
+    } else {
+        window?.$message?.warning('请先修改完红色输入框的数据')
+        return false
+    }
+}
+
+//预览PDF
+const getBussPdfInfo = async (item, showTip = true) => {
+    const pkeyIds = item.pkeyId ? item.pkeyId + '' : ''
+    if (pkeyIds) {
+        const {error, code, data} = await wbsApi.getBussPdfInfo({
+            pkeyId: pkeyIds
+        },false)
+        if (!error && code === 200) {
+            if (data) {
+                window.open(data, '_blank')
+            } else if(showTip) {
+                window?.$message?.warning('PDF错误')
+            }
+        } else {
+            if(showTip) {
+                window?.$message?.warning(data.msg || '获取PDF失败')
+            }
+        }
+    } else {
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//删除本表
+const delClick = async (item) => {
+    const pkeyIds = item.pkeyId ? item.pkeyId + '' : ''
+    if (pkeyIds) {
+        if (isStatus.value !== '3') {
+            const {error, code} = await wbsApi.removeBussTabInfo({
+                pkeyid: pkeyIds,
+                classify: classify.value,
+            })
+            if (!error && code === 200) {
+                window?.$message?.success('操作成功')
+                renewData()
+            }
+        } else {
+            window?.$message?.warning('已上报的资料,不允许删除')
+        }
+    } else {
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//复制本表
+const copyClick = async (item,index) => {
+    const pkeyIds = item.pkeyId ? item.pkeyId + '' : ''
+    if (pkeyIds) {
+        if (isStatus.value !== '3') {
+            if (!item.isRenderTableForm) {
+                await copeBussTab(pkeyIds)
+            } else if (!item.isTableForm) {
+                window?.$message?.warning('暂无表单数据')
+            } else if (item.isRenderTableForm) {
+                const res = await saveExcelBussData(item,index,false)
+                if (res) {
+                    await copeBussTab(pkeyIds)
+                } else {
+                    window?.$message?.warning('复制本表操作失败')
+                }
+            } else {
+                window?.$message?.warning(`数据异常了, isRenderTableForm: ${item.isRenderTableForm}, isTableForm: ${item.isTableForm}, pkeyIds:${pkeyIds}`)
+            }
+        } else {
+            window?.$message?.warning('已上报的资料,不允许复制')
+        }
+    } else {
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+const copeBussTab = async (pkeyIds) => {
+    const {error, code} = await wbsApi.copeBussTab({
+        pkeyId: pkeyIds
+    })
+    if (!error && code === 200) {
+        window?.$message?.success('操作成功')
+        renewData()
+    }
+}
+
+
+//隐藏本表
+const hideClick = async (item) => {
+    const pkeyIds = item.pkeyId ? item.pkeyId + '' : ''
+    if (pkeyIds) {
+        if (isStatus.value !== '3') {
+            const isBussShow = item['isBussShow'] === 2 ? 1 : 2 //状态(1显示 2隐藏)
+            const {error, code} = await wbsApi.showBussTab({
+                pkeyId: pkeyIds,
+                status: isBussShow
+            })
+            if (!error && code === 200) {
+                window?.$message?.success('操作成功')
+                renewData()
+            }
+        } else {
+            window?.$message?.warning('已上报的资料,不允许隐藏')
+        }
+    } else {
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//预览
+const previewClick = async (item,index) => {
+    await getBussPdfInfo(item)
+}
+
+//上传变量
+const uploadModal = ref(false)
+const fileListData = ref([]);
+const uploadData = ref({})
+
+//上传被点击
+const uploadClick = (item,index) => {
+    const pkeyIds = item.pkeyId ? item.pkeyId + '' : ''
+    const keyName = `item-${index}-${pkeyIds}`
+    if (pkeyIds) {
+        if (isStatus.value !== '3' && item.isTableForm) {
+            uploadModal.value = true
+            uploadData.value = getFormDataInit(item,pkeyIds)
+            //获取文件列表
+            getBussFileList(pkeyIds)
+        } else if (!item.isRenderTableForm) {
+            CollapseChange(keyName)
+            window?.$message?.warning('请再次点击上传')
+        } else if (!item.isTableForm) {
+            window?.$message?.warning('暂无表单数据')
+        } else {
+            window?.$message?.warning('已上报的资料,不允许上传')
+        }
+    } else {
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//获取文件列表
+const getBussFileList = async (pkeyId) => {
+    const {error, code, data} = await wbsApi.getBussFileList({
+        pkeyid: pkeyId
+    })
+    if (!error && code === 200) {
+        fileListData.value = getArrValue(data)
+    } else {
+        fileListData.value = []
+    }
+}
+
+//上传文件
+const uploadChange = async ({type}) => {
+    if(type === 'success') {
+        uploadModal.value = false
+        renewData()
+    } else if (type === 'del') {
+        renewData()
+    }
+}
+
+//相关变量
+const tableFormItemNode = ref({})
+
+//菜单数据
+const tableFormMenu = ref([
+    {label: '插入设计值/频率', key: "IDVF"},
+    {label: '插入特殊字符', key: "special"},
+    {label: '关联试验数据', key: "CTD"},
+])
+
+//鼠标右键事件
+const contextMenuRef = ref(null)
+const onRightClick = (event, KeyName, index) => {
+    //取光标位置
+    const specialDom = document.getElementById(KeyName + "")
+    const startPos = specialDom?.selectionStart || 0
+    const endPos = specialDom?.selectionEnd || 0
+    //存储临时信息
+    tableFormItemNode.value = {KeyName, index, startPos, endPos, pkeyId: formKeyIds.value}
+    contextMenuRef.value?.showMenu(event) //展开菜单
+}
+
+//鼠标右键菜单被点击
+const handleMenuSelect = ({key}) => {
+    if (key === 'IDVF') {
+        IDVFModal.value = true
+    } else if (key === 'special') {
+        specialModalShow()
+    } else if (key === 'CTD') {
+        CTDModal.value = true
+    }
+}
+
+//插入设计值
+const IDVFModal = ref(false)
+const formIDVFRef = ref(null)
+const formIDVFModel = ref({type: 1, design: '', size: '', dev: '', key: '', capacity: '', fail: '', pkId: ''})
+
+//插入特殊字符
+const specialModal = ref(false)
+const specialCharacters = ref([
+    '&#57344;', "&#57345;", "&#57346;", "&#57347;", '&#8804;', '&#8805;', '&#8451;',
+    '&#9312;', '&#9313;', '&#9314;', '&#9315;', '&#9316;', '&#9317;', '&#9318;', '&#9319;', '&#9320;', '&#9321;', '&#9322;', '&#9323;',
+    '&#9324;', '&#9325;', '&#9326;', '&#9327;', '&#9328;', '&#9329;', '&#9330;', '&#9331;',
+    "&#8544;", "&#8545;", "&#8546;", "&#8547;", "&#8548;", "&#8549;", "&#8550;", "&#8551;", "&#8552;", "&#8553;", "&#8554;", "&#8555;","K̅"
+])
+
+//输入框验证
+const specialFormRef = ref(null)
+const specialFormModel = ref({val: ''})
+const specialFormRules = {
+    val: {
+        required: true,
+        trigger: "blur",
+        message: "请选择特殊字符代码"
+    }
+}
+//显示插入特殊字符
+const specialRef = ref(null)
+const specialModalShow = () => {
+    specialFormModel.value.val = ''
+    specialModal.value = true
+    nextTick(() => {
+        specialRef.value?.focus();
+    })
+}
+//失去焦点
+const specialPos = ref({start: 0, end: 0})
+const specialInputBlur = (e) => {
+    specialPos.value = {
+        start: e?.target?.selectionStart || 0,
+        end: e?.target?.selectionEnd || 0
+    }
+}
+//点击符号
+const specialClick = (event) => {
+    const text = event?.target?.innerText ?? ''
+    const start = specialPos.value.start
+    const end = specialPos.value.end
+    const form = specialFormModel.value.val
+    specialFormModel.value.val = setPosInsert(start, end, form, text)
+    specialRef.value?.focus();
+    let posVal = start + text.length;
+    nextTick(() => {
+        setPosRange('specialId', posVal)
+    })
+}
+
+//确认插入
+const specialNodeClick = async () => {
+    const res = await formValidate(specialFormRef.value)
+    if (res) {
+        const item = tableFormItemNode.value
+        const form = formData.value[item.index]
+        const val = specialFormModel.value.val ?? ''
+        formData.value[item.index][item.KeyName] = setPosInsert(item.startPos, item.endPos, form[item.KeyName], val)
+        specialModal.value = false
+        specialRef.value?.focus();
+        let posVal = item.startPos + val.length;
+        nextTick(() => {
+            setPosRange(item.KeyName, posVal)
+        })
+    }
+}
+
+//关联试验数据
+const CTDModal = ref(false)
+
+//设计值频率计算
+const IDVFModalSaveClick = async () => {
+    const {pkeyId, KeyName, index} = tableFormItemNode.value
+    if (pkeyId) {
+        const { design, size } = formIDVFModel.value
+        const { error, code, data } = await wbsApi.queryFormulaRange({
+            ...formIDVFModel.value,
+            dev: (!design && !size) ? '±5': '',
+            key: KeyName,
+            pkId: pkeyId
+        })
+        //处理数据
+        const res = getObjNullValue(data)
+        if (!error && code === 200 && res) {
+            Object.keys(data).forEach(key => {
+                formData.value[index][key] = data[key]
+            })
+            IDVFModal.value = false
+        }
+    } else {
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//事件
+const emit = defineEmits(['renew','offsetTop'])
+
+//被点击
+const getOffsetTop = (key = '') => {
+    if (key) {
+        const dom = document.getElementById(key)
+        emit('offsetTop', dom.offsetTop)
+    } else {
+        emit('offsetTop', 0)
+    }
+}
+
+//通知数据更新
+const renewData = () => {
+    emit('renew')
+    ActiveKey.value = ''
+}
+
+//获取表单数据
+const getFormData = () => {
+    const formArr = formData.value;
+    return formArr.filter((item) => {
+        return (item.pkeyId??'') !== '' && item.isCollapseLoad;
+    })
+}
+
+//获取表单效验数据
+const getFormRegExpJson = () => {
+    return deepClone(formRegExpJson.value);
+}
+
+//获取当前展开项
+const getActiveKey = () => {
+    return ActiveKey.value;
+}
+
+//设置当前展开项
+const setActiveKey = (key) => {
+    return ActiveKey.value = key;
+}
+
+// 暴露出去
+defineExpose({
+    getFormData,
+    getFormRegExpJson,
+    getActiveKey,
+    setActiveKey
+})
+</script>
+
+<style lang="scss" scoped>
+.data-fill-list-box {
+    position: relative;
+    //margin-bottom: 25%;
+    .hc-collapse-item-header {
+        flex: 1;
+        position: relative;
+        margin-left: 46px;
+        display: flex;
+        align-items: center;
+        .item-title {
+            flex: 1;
+            position: relative;
+            user-select: none;
+            color: #50545E;
+            font-size: 16px;
+            font-weight: 400;
+            cursor: pointer;
+        }
+        .hc-extra-text-box {
+            position: relative;
+            padding-right: 24px;
+        }
+    }
+    .data-fill-list-item-content {
+        position: relative;
+        display: flex;
+        height: calc(100vh - 386px);
+        .data-fill-table-form-box {
+            position: relative;
+            padding: 24px 20px;
+            height: 100%;
+            overflow: auto;
+            flex: 1;
+            .hc-no-table-form {
+                position: relative;
+                height: 100%;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                .table-form-no {
+                    position: relative;
+                    img {
+                        width: 350px;
+                    }
+                    .desc {
+                        text-align: center;
+                        font-size: 20px;
+                        color: #aaa;
+                    }
+                }
+            }
+        }
+        .data-fill-table-tip-box {
+            width: 240px;
+            position: relative;
+            border-left: 1px solid #E9E9E9;
+            padding: 20px 15px 80px;
+            .tip-title {
+                font-size: 16px;
+                margin-bottom: 10px;
+                display: flex;
+                align-items: center;
+            }
+            .tip-item {
+                margin-bottom: 20px;
+            }
+            .table-tip-foot {
+                position: absolute;
+                bottom: 15px;
+                right: 0;
+                left: 0;
+                display: flex;
+                align-items: center;
+                padding: 0 15px;
+                .tip-left-btn {
+                    flex: 1;
+                    .dow-text {
+                        cursor: pointer;
+                        display: flex;
+                        align-items: center;
+                    }
+                }
+            }
+        }
+    }
+}
+.special-box {
+    position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border: 1px solid #eee;
+    border-radius: 3px;
+    height: 52px;
+    width: 52px;
+    cursor: pointer;
+    user-select: none;
+    transition: color .3s, background-color .3s;
+    &:hover {
+        color: var(--el-color-primary);
+        background-color: var(--el-color-primary-light-8);
+    }
+    .font-EUDC {
+        font-size: 22px;
+    }
+}
+</style>
+
+<style lang="scss">
+.data-fill-list-box {
+    .el-collapse {
+        --el-collapse-header-height: 60px;
+        border: 0;
+        .el-collapse-item {
+            margin: 0 0 16px;
+            background-color: #f1f5f8;
+            border: 1px solid #E9E9E9;
+            border-radius: 4px;
+        }
+        .el-collapse-item__header {
+            background-color: transparent;
+            font-weight: 400;
+            border-bottom: 0;
+            cursor: default;
+            font-size: 14px;
+            .el-collapse-item__arrow {
+                position: absolute;
+                color: #50545E;
+                cursor: pointer;
+                left: 20px;
+                margin: 0;
+            }
+        }
+        .el-collapse-item.is-active .el-collapse-item__header.is-active {
+            background-color: #E7EEF4;
+        }
+        .el-collapse-item__wrap {
+            background-color: transparent;
+            border-bottom: 0;
+            .el-collapse-item__content {
+                position: relative;
+                padding-bottom: 0;
+                font-size: 14px;
+                color: #50545E;
+                line-height: initial;
+            }
+        }
+    }
+}
+
+//插入特殊字符弹窗的输入框
+.data-fill-list-box .data-fill-table-form-box td,
+.data-fill-list-box .data-fill-table-form-box td .el-input .el-input__wrapper .el-input__inner,
+.el-form-item.special-form-item .el-form-item__content .el-input .el-input__wrapper .el-input__inner {
+    font-family: "EUDC", 宋体, v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+}
+</style>

+ 62 - 0
src/views/tentative/detect/test-form.vue

@@ -0,0 +1,62 @@
+<template>
+    <div class="hc-page-box">
+        <HcCard>
+            <template #header>
+                <el-button :type="authBtnTabKey === '1'?'primary':''" hc-btn @click="authBtnTabClick('1')">
+                    <HcIcon name="folder-user"/>
+                    <span>施工质检</span>
+                </el-button>
+                <el-button :type="authBtnTabKey === '2'?'primary':''" hc-btn @click="authBtnTabClick('2')">
+                    <HcIcon name="folder-shield"/>
+                    <span>监理质检</span>
+                </el-button>
+
+            </template>
+            <template #search>
+
+            </template>
+
+            <template #action>
+
+            </template>
+        </HcCard>
+    </div>
+</template>
+
+<script setup>
+import {ref, watch, onMounted} from "vue";
+import {useAppStore} from "~src/store";
+import {useRoute} from 'vue-router'
+
+//变量
+const useRoutes = useRoute()
+const useAppState = useAppStore()
+const projectId = ref(useAppState.getProjectId);
+const contractId = ref(useAppState.getContractId);
+
+//路由参数
+const routerQuery = useRoutes?.query;
+//存储目录格式 1按部位存储,2按日期存储
+const dataId = routerQuery?.id || '';
+const dataType = parseInt(routerQuery?.type + '') || 1;
+const fileType = parseInt(routerQuery?.fileType + '') || 2;
+
+//渲染完成
+onMounted(() => {
+
+})
+
+//身份按钮切换数据
+const authBtnTabKey = ref('1')
+const authBtnTabClick = (val) => {
+    if (val !== authBtnTabKey.value) {
+        authBtnTabKey.value = val
+        //getTableDataAll()
+    }
+}
+
+</script>
+
+<style lang="scss" scoped>
+@import "../../../styles/tentative/detect/test-form.scss";
+</style>

+ 41 - 13
src/views/tentative/detect/test.vue

@@ -21,31 +21,31 @@
         <div class="hc-page-content-box">
             <HcCard :scrollbar="false" actionSize="lg">
                 <template #header>
-                    <HcTooltip keys="tentative_detect_outside_add">
+                    <HcTooltip keys="tentative_detect_test_add">
                         <el-button type="primary" hc-btn @click="addFormModalClick">
                             <HcIcon name="add-circle"/>
                             <span>新增</span>
                         </el-button>
                     </HcTooltip>
-                    <HcTooltip keys="tentative_detect_outside_copy">
+                    <HcTooltip keys="tentative_detect_test_copy">
                         <el-button hc-btn>
                             <HcIcon name="file-copy-2"/>
                             <span>复制</span>
                         </el-button>
                     </HcTooltip>
-                    <HcTooltip keys="tentative_detect_outside_del">
+                    <HcTooltip keys="tentative_detect_test_del">
                         <el-button hc-btn @click="delModalClick">
                             <HcIcon name="delete-bin-2"/>
                             <span>删除</span>
                         </el-button>
                     </HcTooltip>
-                    <HcTooltip keys="tentative_detect_outside_edit">
+                    <HcTooltip keys="tentative_detect_test_print">
                         <el-button hc-btn>
                             <HcIcon name="printer"/>
                             <span>批量打印</span>
                         </el-button>
                     </HcTooltip>
-                    <HcTooltip keys="tentative_detect_outside_edit">
+                    <HcTooltip keys="tentative_detect_test_null">
                         <el-button hc-btn>
                             <HcIcon name="printer"/>
                             <span>打印空表</span>
@@ -78,13 +78,14 @@
                 </template>
                 <HcTable ref="tableRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" isCheck @selection-change="tableSelection">
                     <template #key5="{row}">
-                        <span class="text-link" @click="tableRowEdit(row)">{{row?.key5}}</span>
+                        <span class="text-link" @click="tableRowEdit(row)" v-if="btn_edit">{{row?.key5}}</span>
+                        <span v-else>{{row?.key5}}</span>
                     </template>
                     <template #action="{row}">
-                        <HcTooltip keys="tentative_material_approach_annex">
+                        <HcTooltip keys="tentative_detect_test_annex">
                             <el-button type="primary" size="small" plain @click="viewAttachmentModalClick(row)">附件</el-button>
                         </HcTooltip>
-                        <HcTooltip keys="tentative_material_approach_sampling">
+                        <HcTooltip keys="tentative_detect_test_info">
                             <el-button type="primary" size="small" plain @click="samplingRecordModalClick(row)">样品信息</el-button>
                         </HcTooltip>
                     </template>
@@ -125,6 +126,7 @@
 
 <script setup>
 import {ref, watch, onMounted} from "vue";
+import {useRouter} from 'vue-router'
 import {useAppStore} from "~src/store";
 import WbsTree from "../../data-fill/components/WbsTree.vue"
 import {getStoreData, setStoreData} from '~src/utils/storage'
@@ -132,25 +134,35 @@ import HcDragUpload from "./components/HcDragUpload.vue"
 import notableform from '~src/assets/view/notableform.svg';
 
 //变量
+const router = useRouter()
 const useAppState = useAppStore()
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 const projectInfo = ref(useAppState.getProjectInfo);
 const isCollapse = ref(useAppState.getCollapse)
+const isBubble = ref(useAppState.getBubble);
 
 //监听
 watch(() => [
-    useAppState.getCollapse
-], ([Collapse]) => {
+    useAppState.getCollapse,
+    useAppState.getBubble,
+], ([Collapse,bubble]) => {
     isCollapse.value = Collapse
+    isBubble.value = bubble
 })
 
+//获取气泡数据
+const getButtonsVal = (value) => {
+    return useAppState.getButtonsVal(value)
+}
+
 //自动展开缓存
 const treeAutoExpandKeys = ref(getStoreData('wbsTreeExpandKeys') || [])
+const btn_edit = ref(false)
 
 //渲染完成
 onMounted(() => {
-
+    btn_edit.value = getButtonsVal('tentative_detect_test_edit')
 })
 
 const userData = ref([
@@ -253,12 +265,28 @@ const tableSelection = (rows) => {
 
 //新增
 const addFormModalClick = () => {
-
+    router.push({
+        path: '/tentative/detect/test-form',
+        query: {
+            //wbsId: queryKey.value,  //树节点ID
+            //dataType: dataType,     //存储目录格式 1按部位存储,2按日期存储
+            //fileType: fileType,     //文件类型,1视频文件,2图片文件
+            //classifyId: dataId,     //classifyId,分类ID,
+        }
+    })
 }
 
 //编辑
 const tableRowEdit = () => {
-
+    router.push({
+        path: '/tentative/detect/test-form',
+        query: {
+            //wbsId: queryKey.value,  //树节点ID
+            //dataType: dataType,     //存储目录格式 1按部位存储,2按日期存储
+            //fileType: fileType,     //文件类型,1视频文件,2图片文件
+            //classifyId: dataId,     //classifyId,分类ID,
+        }
+    })
 }
 
 //删除