ZaiZai 3 gadi atpakaļ
vecāks
revīzija
df023d70b7
34 mainītis faili ar 2482 papildinājumiem un 2921 dzēšanām
  1. 2 2
      package.json
  2. 2 2
      src/api/modules/other-file/imageData.js
  3. 93 0
      src/components/hc-sb-table/index.vue
  4. 1 0
      src/global/components/hc-card/index.vue
  5. 9 0
      src/global/components/hc-menu-simple/index.vue
  6. 1 1
      src/global/components/hc-report-modal/index.vue
  7. 1 0
      src/global/components/hc-tasks-user/index.vue
  8. 2 2
      src/global/components/hc-tasks-user/style.scss
  9. 167 0
      src/global/components/hc-uploads/index.vue
  10. 2 0
      src/global/components/index.js
  11. 1 1
      src/layout/index.vue
  12. 1 1
      src/layout/modules/MenuBar.vue
  13. 9 0
      src/styles/app/element.scss
  14. 11 1
      src/styles/app/main.scss
  15. 0 2
      src/styles/gauge/bezier.scss
  16. 0 26
      src/styles/other-file/image-data.scss
  17. 55 0
      src/styles/other-file/image-form.scss
  18. 104 0
      src/styles/other-file/image-view.scss
  19. 19 0
      src/styles/tasks/hc-data.scss
  20. 8 15
      src/styles/tasks/message.scss
  21. 5 2
      src/views/data-fill/query.vue
  22. 4 4
      src/views/data-fill/wbs.vue
  23. 607 21
      src/views/gauge/bezier.vue
  24. 0 787
      src/views/gauge/bezier_a.vue
  25. 97 0
      src/views/other-file/components/HcTreeData.vue
  26. 158 0
      src/views/other-file/components/WbsTree.vue
  27. 141 203
      src/views/other-file/image-data.vue
  28. 87 437
      src/views/other-file/image-form.vue
  29. 267 301
      src/views/other-file/image-view.vue
  30. 136 234
      src/views/tasks/flow.vue
  31. 296 647
      src/views/tasks/hc-data.vue
  32. 70 125
      src/views/tasks/message-data.vue
  33. 118 99
      src/views/tasks/sign-admin.vue
  34. 8 8
      yarn.lock

+ 2 - 2
package.json

@@ -10,7 +10,7 @@
         "axios": "^0.27.2",
         "crypto-js": "^4.1.1",
         "echarts": "^5.3.3",
-        "element-plus": "^2.2.14",
+        "element-plus": "^2.2.15",
         "js-base64": "^3.7.2",
         "js-cookie": "^3.0.1",
         "js-md5": "^0.7.3",
@@ -19,7 +19,7 @@
         "naive-ui": "^2.32.2",
         "pinia": "^2.0.20",
         "vue": "^3.2.37",
-        "vue-router": "^4.1.3",
+        "vue-router": "^4.1.4",
         "vue-utils-plus": "^1.0.2",
         "vuedraggable": "^4.1.0"
     },

+ 2 - 2
src/api/modules/other-file/imageData.js

@@ -82,12 +82,12 @@ export default {
         });
     },
     //影音资料览(图片)
-    async imageClassificationFile(form) {
+    async imageClassificationFile(form, msg= true) {
         return httpApi({
             url: '/api/blade-business/imageClassificationFile/preview',
             method: 'post',
             params: form
-        });
+        }, msg);
     },
     //下载
     async batchDownloadFileToZip(form) {

+ 93 - 0
src/components/hc-sb-table/index.vue

@@ -0,0 +1,93 @@
+<template>
+    <div class="hc-sb-table">
+        <template v-for="item in datas">
+            <div class="item" :class="curKey === item.key ? 'active' : ''" @click="tabClick(item)">
+                <HcIcon :name="item.icon" class="icon"/>
+                <span class="name">{{item.label}}</span>
+            </div>
+        </template>
+    </div>
+</template>
+
+<script setup>
+import { ref, watch } from "vue";
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => []
+    },
+    cur: {
+        type: [String,Number],
+        default: ''
+    }
+})
+const curKey = ref(props.cur)
+watch(() => [
+    props.cur,
+], ([cur]) => {
+    curKey.value = cur
+})
+//事件
+const emit = defineEmits(['tabClick'])
+const tabClick = (item) => {
+    if (curKey.value !== item.key) {
+        curKey.value = item.key;
+        emit('tabClick', item.key)
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.hc-sb-table {
+    position: relative;
+    .item {
+        position: relative;
+        display: inline-flex;
+        background-color: #E9EFF5;
+        color: #838791;
+        align-items: center;
+        padding: 12px 20px;
+        overflow: visible;
+        transition: 0.2s;
+        &:before {
+            content: "";
+            background-color: #CCCCCC;
+            position: absolute;
+            height: 14px;
+            width: 1px;
+            right: 0;
+        }
+        &:first-child {
+            border-radius: 10px 0 0 0;
+        }
+        &:last-child {
+            border-radius: 0 10px 0 0;
+            &:before {
+                width: 0;
+            }
+        }
+        .icon {
+            font-size: 18px;
+            margin-right: 5px;
+        }
+        .name {
+            font-size: 14px;
+        }
+        &:not(.active):hover {
+            background: var(--el-color-primary-light-9);
+        }
+        &:not(.active) {
+            cursor: pointer;
+        }
+        &.active {
+            background: #f1f5f8;
+            color: var(--el-color-primary);
+            box-shadow: -8px -11px 20px 4px rgba(32, 37, 50,  0.03);
+            z-index: 2;
+            .icon,  .name {
+                z-index: 2;
+            }
+        }
+    }
+}
+</style>

+ 1 - 0
src/global/components/hc-card/index.vue

@@ -95,6 +95,7 @@ const isSlotSearchBar = ref(!!slots.search);
         position: relative;
         display: flex;
         align-items: center;
+        height: 100%;
         .hc-card-header {
             position: relative;
             flex: 1;

+ 9 - 0
src/global/components/hc-menu-simple/index.vue

@@ -6,6 +6,7 @@
                     <HcIcon :name="item?.icon" fill/>
                 </div>
                 <div class="label-box truncate">{{item?.label}}</div>
+                <el-badge :value="item?.badge" v-if="item?.badge > 0"/>
             </div>
         </template>
     </div>
@@ -107,3 +108,11 @@ const MenuClick = (item) => {
     }
 }
 </style>
+
+<style lang="scss" scoped>
+.hc-menu-simple-box .item-box .el-badge {
+    position: absolute;
+    display: flex;
+    right: 12px;
+}
+</style>

+ 1 - 1
src/global/components/hc-report-modal/index.vue

@@ -36,9 +36,9 @@
 
 <script setup>
 import {ref,watch,onMounted} from "vue";
-import {getArrValue,getIndex,formValidate} from "vue-utils-plus"
 import tasksFlowApi from '~api/tasks/flow';
 import {ApprovalApi} from '~api/other';
+import {getArrValue,getIndex,formValidate} from "vue-utils-plus"
 
 const props = defineProps({
     show: {

+ 1 - 0
src/global/components/hc-tasks-user/index.vue

@@ -275,6 +275,7 @@ const sureSignUserClick = () => {
         --el-icon-size: 14px;
         padding: 0 10px;
         height: 26px;
+        margin: 4px 0;
     }
 }
 .hc-tasks-user-modal-content-box {

+ 2 - 2
src/global/components/hc-tasks-user/style.scss

@@ -6,13 +6,13 @@
         border-radius: 4px;
         padding: 0 12px;
         cursor: pointer;
-        height: 40px;
+        min-height: 40px;
         .tag-user-list {
             position: relative;
             display: flex;
             align-items: center;
             flex-flow: row wrap;
-            height: inherit;
+            min-height: inherit;
             .tasks-placeholder {
                 color: #a9abb2;
                 font-size: 14px;

+ 167 - 0
src/global/components/hc-uploads/index.vue

@@ -0,0 +1,167 @@
+<template>
+    <div class="hc-uploads-box" v-loading="spinShow">
+        <el-upload ref="uploadRef" :file-list="fileListData" :action="action" :headers="getTokenHeader()" :data="uploadData" :limit="limit" :accept="accept"
+                   list-type="picture-card" :multiple="limit > 1"  :disabled="uploadDisabled" :on-preview="uploadPreview"
+                   :on-success="uploadSuccess" :on-exceed="uploadExceed" :on-error="uploadError"
+                   :before-upload="beforeUpload" :on-progress="uploadprogress" :on-remove="uploadRemove">
+            <HcIcon name="add" class="hc-upload-icon"/>
+        </el-upload>
+        <el-image-viewer v-if="showViewer" :initial-index="initialIndex" :url-list="previewFileList" @close="showViewerClose"/>
+    </div>
+</template>
+
+<script setup>
+import {ref,watch,onMounted} from "vue";
+import {getTokenHeader} from '~src/api/request/header';
+import {getIndex, isSize} from "vue-utils-plus"
+import {genFileId} from "element-plus";
+
+const props = defineProps({
+    fileList: {
+        type: Array,
+        default: () => ([])
+    },
+    datas: {
+        type: Object,
+        default: () => ({})
+    },
+    action: {
+        type: String,
+        default: "/api/blade-resource/oss/endpoint/put-file"
+    },
+    accept: {
+        type: String,
+        default: "image/png,image/jpg,image/jpeg"
+    },
+    limit: {
+        type: Number,
+        default: 1
+    },
+    size: {
+        type: Number,
+        default: 30
+    },
+    viewer: {
+        type: Boolean,
+        default: true
+    },
+})
+
+//变量
+const uploadRef = ref(null)
+const uploadData = ref(props.datas)
+const fileListData = ref(props.fileList);
+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 showViewerClose = () => {
+    showViewer.value = false
+}
+
+//事件
+const emit = defineEmits(['change', 'del', 'preview'])
+
+//上传前
+const spinShow = ref(false)
+const beforeFileNum = ref(0)
+const beforeUpload = async (file) => {
+    if (isSize(file?.size, props.size)) {
+        beforeFileNum.value ++;
+        spinShow.value = true
+        return true;
+    } else {
+        window?.$message?.warning(`文件大小, 不能过${props.size}M!`);
+        return false;
+    }
+}
+
+//超出限制时
+const uploadExceed = (files) => {
+    //上传一个文件时,重置
+    if (props.limit === 1) {
+        uploadRef.value?.clearFiles()
+        const file = files[0]
+        file.uid = genFileId()
+        uploadRef.value?.handleStart(file)
+    } else {
+        window?.$message?.warning(`请上传 ${props.accept} 格式的文件,文件大小不超过${props.size}M`);
+    }
+}
+
+//上传中
+const uploadprogress = () => {
+    uploadDisabled.value = true
+}
+
+//上传完成
+const finishFileNum = ref(0)
+const uploadSuccess = (response,uploadFile,uploadFiles) => {
+    finishFileNum.value ++;
+    if (beforeFileNum.value === finishFileNum.value) {
+        spinShow.value = false
+        uploadDisabled.value = false
+        emit('change', {type: 'success', fileList: uploadFiles})
+    }
+}
+
+//上传失败
+const errorFileNum = ref(0)
+const uploadError = () => {
+    errorFileNum.value ++;
+    window?.$message?.error('上传失败');
+    const num = finishFileNum.value + errorFileNum.value;
+    if (beforeFileNum.value === num) {
+        const fileList = fileListData.value ?? [];
+        spinShow.value = false
+        uploadDisabled.value = false
+        console.log(fileList)
+        emit('change', {type: 'error', fileList: fileListData.value})
+    }
+}
+
+//预览
+const showViewer = ref(false)
+const initialIndex = ref(-1)
+const previewFileList = ref([])
+const uploadPreview = (file) => {
+    let fileArr = getUploadFileUrl()
+    const fileList = fileListData.value ?? [];
+    const index = getIndex(fileList, 'uid', file?.uid)
+    if (props.viewer) {
+        previewFileList.value = fileArr
+        initialIndex.value = index
+        showViewer.value = true
+    } else {
+        emit('preview', {index, fileArr, fileList})
+    }
+}
+
+//获取文件URL
+const getUploadFileUrl = () => {
+    let fileArr = [], fileList = fileListData.value ?? [];
+    fileList.forEach(item => {
+        fileArr.push(item?.response?.data?.link)
+    })
+    return fileArr
+}
+
+//删除文件
+const uploadRemove = (row) => {
+    emit('del', {row, fileList: fileListData.value})
+}
+</script>

+ 2 - 0
src/global/components/index.js

@@ -3,6 +3,7 @@ import HcIcon from './hc-icon/index.vue'
 import HcCard from './hc-card/index.vue'
 import HcPages from './hc-page/index.vue'
 import HcDrawer from './hc-drawer/index.vue'
+import HcUploads from './hc-uploads/index.vue'
 import HcCounter from './hc-counter/index.vue'
 import HcTooltip from './hc-tooltip/index.vue'
 import HcMenuSimple from './hc-menu-simple/index.vue'
@@ -19,6 +20,7 @@ export const setupComponents = (App) => {
     App.component('HcCard', HcCard)
     App.component('HcPages', HcPages)
     App.component('HcDrawer', HcDrawer)
+    App.component('HcUploads', HcUploads)
     App.component('HcCounter', HcCounter)
     App.component('HcTooltip', HcTooltip)
     App.component('HcMenuSimple', HcMenuSimple)

+ 1 - 1
src/layout/index.vue

@@ -51,7 +51,7 @@
 <script setup>
 import {onMounted, ref, nextTick, watch} from "vue";
 import {useRouter, useRoute} from 'vue-router'
-import {useAppStore} from "~src/store/index";
+import {useAppStore} from "~src/store";
 import MenuBar from "./modules/MenuBar.vue"
 import HelpInfoBar from "./modules/HelpInfoBar.vue"
 import UserInfoBar from "./modules/UserInfoBar.vue"

+ 1 - 1
src/layout/modules/MenuBar.vue

@@ -120,7 +120,7 @@ const MenuClick = (item) => {
         .hc-aside-menu-item {
             --radius-size: 20px;
             background-color: var(--el-color-primary);
-            box-shadow: 4px 4px 8px 0 rgba(0, 0, 0, 0.3), 0 -6px 8px 0 #707070;
+            box-shadow: 0 0 8px 2px rgba(0, 0, 0, 0.17), 0 0 8px 2px rgba(112, 112, 112, 0.58);
             &::before, &::after {
                 content: '';
                 display: block;

+ 9 - 0
src/styles/app/element.scss

@@ -383,3 +383,12 @@
     display: flex;
     align-items: center;
 }
+
+//无名称
+.el-form-item[no-label] .el-form-item__label-wrap {
+    margin-left: 0 !important;
+}
+
+.el-form--large.el-form--label-top .el-form-item .el-form-item__label {
+    min-height: 22px;
+}

+ 11 - 1
src/styles/app/main.scss

@@ -36,7 +36,17 @@ html, body, #app {
     user-select: none;
 }
 
-
+.lr-dialog-footer {
+    position: relative;
+    display: flex;
+    align-items: flex-end;
+    justify-content: space-between;
+    .left {
+        .el-button + .el-button {
+            margin-left: 10px;
+        }
+    }
+}
 
 
 .n-layout .n-layout-scroll-container {

+ 0 - 2
src/styles/gauge/bezier.scss

@@ -24,6 +24,4 @@
 .admin-part-data-table {
     position: relative;
     max-height: 400px;
-    overflow: auto;
 }
-

+ 0 - 26
src/styles/other-file/image-data.scss

@@ -1,29 +1,3 @@
-.hc-image-data-content-box {
-    position: relative;
-    height: calc(100% - 60px);
-    .header-title-box {
-        position: relative;
-        flex: 1;
-        padding-right: 30px;
-        color: inherit;
-        font-size: 16px;
-    }
-    .hc-collapse-list-box {
-        position: relative;
-        border-radius: 0 0 3px 3px;
-        .item-box {
-            position: relative;
-            padding: 12px 40px;
-            cursor: pointer;
-            transition: background-color .3s, color .3s;
-            &:hover {
-                color: var(--hc-primary);
-                background-color: var(--hc-primary-light-7);
-            }
-        }
-    }
-}
-
 .hc-layout-box {
     display: flex;
     position: relative;

+ 55 - 0
src/styles/other-file/image-form.scss

@@ -0,0 +1,55 @@
+.hc-layout-box {
+    display: flex;
+    position: relative;
+    height: 100%;
+    .hc-layout-left-box {
+        width: 382px;
+        position: relative;
+        background: #f1f5f8;
+        border-radius: 10px;
+        box-shadow: -2px 0 10px 0 rgba(32,37,50,0.03), 0 10px 21px 20px rgba(32,37,50,0.03);
+        .horizontal-drag-line {
+            position: absolute;
+            right: 0;
+            top: 0;
+            width: 2px;
+            height: 100%;
+            user-select: none;
+            cursor: col-resize;
+            background-color: #00000000;
+        }
+        .hc-project-box {
+            position: relative;
+            padding: 15px 24px;
+            display: flex;
+            align-items: flex-start;
+            border-bottom: 1px solid #E9E9E9;
+            .hc-project-icon-box {
+                font-size: 30px;
+                color: var(--el-color-primary);
+            }
+            .project-name-box {
+                flex: auto;
+                position: relative;
+                overflow: hidden;
+                .project-alias {
+                    color: var(--el-color-primary);
+                }
+                .project-name {
+                    margin-top: 6px;
+                    color: #838791;
+                }
+            }
+        }
+        .hc-tree-box {
+            position: relative;
+            padding: 15px 20px;
+            height: calc(100% - 80px);
+        }
+    }
+    .hc-layout-content-box {
+        flex: 1;
+        position: relative;
+        margin-left: 24px;
+    }
+}

+ 104 - 0
src/styles/other-file/image-view.scss

@@ -0,0 +1,104 @@
+.hc-layout-box {
+    display: flex;
+    position: relative;
+    height: 100%;
+    .hc-layout-left-box {
+        width: 382px;
+        position: relative;
+        background: #f1f5f8;
+        border-radius: 10px;
+        box-shadow: -2px 0 10px 0 rgba(32,37,50,0.03), 0 10px 21px 20px rgba(32,37,50,0.03);
+        .horizontal-drag-line {
+            position: absolute;
+            right: 0;
+            top: 0;
+            width: 2px;
+            height: 100%;
+            user-select: none;
+            cursor: col-resize;
+            background-color: #00000000;
+        }
+        .hc-project-box {
+            position: relative;
+            padding: 15px 24px;
+            display: flex;
+            align-items: flex-start;
+            border-bottom: 1px solid #E9E9E9;
+            .hc-project-icon-box {
+                font-size: 30px;
+                color: var(--el-color-primary);
+            }
+            .project-name-box {
+                flex: auto;
+                position: relative;
+                overflow: hidden;
+                .project-alias {
+                    color: var(--el-color-primary);
+                }
+                .project-name {
+                    margin-top: 6px;
+                    color: #838791;
+                }
+            }
+        }
+        .hc-tree-box {
+            position: relative;
+            padding: 15px 20px;
+            height: calc(100% - 80px);
+            &.date-tree {
+                height: 100%;
+            }
+        }
+    }
+    .hc-layout-content-box {
+        flex: 1;
+        position: relative;
+        margin-left: 24px;
+        .hc-table-col-item {
+            position: relative;
+            display: flex;
+            .img-box {
+                height: 90px;
+                width: 90px;
+                margin-right: 16px;
+                .hc-image {
+                    height: 90px;
+                    width: 90px;
+                    border-radius: 5px;
+                }
+                video {
+                    height: 90px;
+                    width: 90px;
+                    border-radius: 5px;
+                    object-fit: fill;
+                }
+            }
+            .content-box {
+                flex: 1;
+                position: relative;
+                height: 90px;
+                .title {
+                    color: #1a1a1a;
+                    font-weight: bold;
+                    font-size: 14px;
+                }
+                .shootingUser {
+                    font-size: 12px;
+                }
+                .shootingTimeStr {
+                    color: #a1a1a1;
+                    font-size: 12px;
+                }
+                .fileSize {
+                    color: #a1a1a1;
+                    font-size: 12px;
+                }
+            }
+        }
+    }
+}
+
+.preview-video {
+    width: 100%;
+    max-height: 500px;
+}

+ 19 - 0
src/styles/tasks/hc-data.scss

@@ -0,0 +1,19 @@
+.hc-layout-box {
+    position: relative;
+    height: 100%;
+    .hc-content-box {
+        position: relative;
+        height: calc(100% - 45px);
+    }
+}
+
+.obj-item-cell {
+    position: relative;
+    display: flex;
+    align-items: center;
+    margin-top: 24px;
+    .label {
+        margin-right: 20px;
+        width: 126px;
+    }
+}

+ 8 - 15
src/styles/tasks/message.scss

@@ -1,24 +1,17 @@
 .hc-layout-box {
-    display: flex;
     position: relative;
-    height: calc(100% - 60px);
-    .hc-layout-menu-box {
+    height: 100%;
+    display: flex;
+    .hc-layout-left-box {
+        width: 260px;
         position: relative;
-        background: white;
-        overflow: auto;
-        width: 220px;
-        border: 1px solid #EEEEEE;
-        margin-bottom: 15px;
+        background: #f1f5f8;
+        border-radius: 10px;
+        box-shadow: -2px 0 10px 0 rgba(32,37,50,0.03), 0 10px 21px 20px rgba(32,37,50,0.03);
     }
     .hc-layout-content-box {
         flex: 1;
-        overflow: auto;
         position: relative;
-        padding: 0 24px 15px 20px;
+        margin-left: 24px;
     }
 }
-.hc-card-header {
-    position: relative;
-    font-size: initial;
-    font-weight: initial;
-}

+ 5 - 2
src/views/data-fill/query.vue

@@ -115,7 +115,7 @@
                 </template>
                 <el-scrollbar>
                     <div class="hc-table-ref-box">
-                        <el-table ref="recycleTableRef" hc :data="tableListData" :loading="tableLoading" stripe @selection-change="tableSelectionChange">
+                        <el-table ref="tableListRef" hc :data="tableListData" :loading="tableLoading" stripe @selection-change="tableSelectionChange">
                             <el-table-column type="selection" width="50" />
                             <el-table-column prop="num" label="序号" width="80">
                                 <template #default="scope">
@@ -145,7 +145,7 @@
 
 <script setup>
 import {ref,watch,onMounted} from "vue";
-import {useAppStore} from "~src/store/index";
+import {useAppStore} from "~src/store";
 import WbsTree from "./components/WbsTree.vue"
 import HcTreeData from "./components/HcTreeData.vue"
 import {getStoreData, setStoreData} from '~src/utils/storage'
@@ -325,10 +325,13 @@ const pageChange = ({current, size}) => {
 }
 
 //获取数据
+const tableListRef = ref(null)
 const tableLoading = ref(false)
 const tableListData = ref([])
 const getTableData = async () => {
     if (!!searchForm.value.wbsId) {
+        tableListRef.value?.clearSelection()
+        tableCheckedKeys.value = []
         tableLoading.value = true
         const { error, code, data } = await queryApi.getPageData({
             projectId: projectId.value,

+ 4 - 4
src/views/data-fill/wbs.vue

@@ -499,7 +499,7 @@ const wbsElTreeClick = ({node, data, keys}) => {
     primaryKeyId.value = data?.primaryKeyId || ''
     setStoreData('wbsTreeExpandKeys',keys)
     TreeAutoExpandKeys.value = keys || []
-    searchNodeAllTable()
+    getTableDataAll()
 }
 //树菜单被点击
 const ElTreeMenuClick = async ({key,node,data}) => {
@@ -524,7 +524,7 @@ const NodeTreeDblClick = ({node,data}) => {
     nodeDataInfo.value = data
     primaryKeyId.value = data?.primaryKeyId || ''
     isDrawer.value = true;
-    searchNodeAllTable()
+    getTableDataAll()
 }
 const drawerClose = () => {
     isDrawer.value = false;
@@ -1003,7 +1003,7 @@ const queryNodeStatus = async () => {
     })
     //1 未填报,2待上报,3已上报
     if (!error && code === 200) {
-        NodeStatus.value = getObjNullValue(data?.data) || '1'
+        NodeStatus.value = data ?? '1'
     } else {
         NodeStatus.value = '1'
     }
@@ -1019,7 +1019,7 @@ const reportModalClick = () => {
     const rows = ListItemDatas.value;
     reportIds.value = info['contractIdRelation'] ? info['id'] : info['primaryKeyId']
     if (rows.length > 0) {
-        reportTaskName.value = rows.length > 1?`${rows[0].name}等${rows.length}个文件`:rows[0].name
+        reportTaskName.value = rows.length > 1?`${rows[0].deptName}等${rows.length}个文件`:rows[0].deptName
         reportAddition.value = {
             classify: authBtnTabKey.value,
             contractIdRelation: info['contractIdRelation'],

+ 607 - 21
src/views/gauge/bezier.vue

@@ -10,13 +10,13 @@
                 </HcTooltip>
                 <HcTooltip keys="gauge-bezier-to">
                     <el-button hc-btn @click="showToModalClick">
-                        <HcIcon name="add_box"/>
+                        <HcIcon name="sync_alt"/>
                         <span>转换坐标</span>
                     </el-button>
                 </HcTooltip>
                 <HcTooltip keys="gauge-bezier-pile">
                     <el-button hc-btn @click="pileModalClick">
-                        <HcIcon name="add_box"/>
+                        <HcIcon name="device_hub"/>
                         <span>逐桩坐标</span>
                     </el-button>
                 </HcTooltip>
@@ -27,7 +27,7 @@
                     </el-button>
                 </HcTooltip>
                 <HcTooltip keys="gauge-bezier-export">
-                    <el-button hc-btn @click="exportModalClick">
+                    <el-button hc-btn :loading="downloadLoading" @click="exportModalClick">
                         <HcIcon name="download"/>
                         <span>导出</span>
                     </el-button>
@@ -35,8 +35,8 @@
             </template>
             <template #extra>
                 <div class="w-60">
-                    <el-select v-model="searchForm.partId" block clearable size="large" @change="searchClick">
-                        <el-option v-for="item in partData" :label="item.name" :value="item.id" placeholder="片段查询"/>
+                    <el-select v-model="searchForm.partId" block clearable size="large" placeholder="片段查询" @change="searchClick">
+                        <el-option v-for="item in partData" :label="item.name" :value="item.id"/>
                     </el-select>
                 </div>
                 <HcTooltip keys="gauge-bezier-add-part">
@@ -51,7 +51,40 @@
                 </HcTooltip>
             </template>
             <el-scrollbar>
-                123456
+                <div class="hc-table-ref-box">
+                    <el-table hc :data="tableData" :loading="tableLoading" stripe>
+                        <el-table-column prop="num" label="序号" width="80">
+                            <template #default="scope">
+                                {{scope.$index + 1}}
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="name" label="里程">
+                            <template #default="scope">{{scope.row?.valueStr}}~{{scope.row?.valueEndStr}}</template>
+                        </el-table-column>
+                        <el-table-column prop="orderNum" label="排序"/>
+                        <el-table-column prop="l" label="长度"/>
+                        <el-table-column prop="angle" label="方位角"/>
+                        <el-table-column prop="type" label="类型">
+                            <template #default="scope">
+                                {{getTypeName(scope.row?.type)}}
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="swing" label="转向"/>
+                        <el-table-column prop="xxStr" label="X"/>
+                        <el-table-column prop="yyStr" label="Y"/>
+                        <el-table-column prop="r" label="半径"/>
+                        <el-table-column label="操作" align="center" width="130">
+                            <template #default="scope">
+                                <HcTooltip keys="gauge-station-edit">
+                                    <el-button type="primary" size="small" text @click="handleTableEdit(scope.row)">编辑</el-button>
+                                </HcTooltip>
+                                <HcTooltip keys="gauge-station-del">
+                                    <el-button type="danger" size="small" text @click="handleTableDelete(scope.row)">删除</el-button>
+                                </HcTooltip>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                </div>
             </el-scrollbar>
             <template #action>
                 <HcPages :pages="searchForm" @change="pageChange"/>
@@ -65,21 +98,24 @@
                         <el-table hc :data="AdminPartTableData" stripe>
                             <el-table-column prop="name" label="片段名称">
                                 <template #default="scope">
-                                    <el-input v-model="scope.row.name" placeholder="片段名称"/>
+                                    <el-input v-model="scope.row.name" placeholder="片段名称" v-if="scope.row.isEdit"/>
+                                    <div v-else>{{scope.row.name}}</div>
                                 </template>
                             </el-table-column>
-                            <el-table-column prop="name" label="桩号前缀">
+                            <el-table-column prop="prefix" label="桩号前缀">
                                 <template #default="scope">
-                                    <el-input v-model="scope.row.prefix" placeholder="桩号前缀"/>
+                                    <el-input v-model="scope.row.prefix" placeholder="桩号前缀" v-if="scope.row.isEdit"/>
+                                    <div v-else>{{scope.row.prefix}}</div>
                                 </template>
                             </el-table-column>
                             <el-table-column label="操作" align="center" width="130">
                                 <template #default="scope">
-                                    <HcTooltip keys="gauge-station-edit">
-                                        <el-button type="primary" size="small" text @click="handleAdminPartdit(scope.row)">编辑</el-button>
+                                    <el-button type="primary" size="small" text @click="handleAdminPartSave(scope.row)" v-if="scope.row.isEdit">保存</el-button>
+                                    <HcTooltip keys="gauge-station-edit" v-else>
+                                        <el-button type="primary" size="small" text @click="handleAdminPartEdit(scope.row)">编辑</el-button>
                                     </HcTooltip>
                                     <HcTooltip keys="gauge-station-del">
-                                        <el-button type="danger" size="small" text @click="handleAdminPartDelete(scope.row)">删除</el-button>
+                                        <el-button type="danger" size="small" text @click="handleAdminPartDelete(scope.row,scope.$index)">删除</el-button>
                                     </HcTooltip>
                                 </template>
                             </el-table-column>
@@ -94,21 +130,191 @@
                 </div>
             </template>
         </el-dialog>
-
+        <!--新增片段弹框-->
+        <el-dialog v-model="showAddPartModal" title="新增片段" width="38rem" draggable custom-class="hc-modal-border">
+            <el-form ref="partFormRef" :model="partForm" :rules="partRules" label-width="auto" size="large">
+                <el-form-item label="名称" prop="name">
+                    <el-input v-model="partForm.name" placeholder="请输入名称"/>
+                </el-form-item>
+                <el-form-item label="桩号前缀" prop="prefix">
+                    <el-input v-model="partForm.prefix" placeholder="只允许输入大写的英文字母"/>
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="showAddPartModal = false">取消</el-button>
+                    <el-button type="primary" hc-btn :loading="savePartLoading" @click="savePartInfo">保存</el-button>
+                </div>
+            </template>
+        </el-dialog>
+        <!--添加/编辑线元弹框-->
+        <el-dialog v-model="showLineEleModal" :title="(formLineEleValue.id === -1 || !formLineEleValue.id)?'添加线元':'编辑线元'" draggable width="40rem" custom-class="hc-modal-border">
+            <el-form :model="formLineEleValue" label-width="auto" size="large">
+                <el-form-item label="类型">
+                    <el-radio-group v-model="formLineEleValue.type">
+                        <el-radio v-for="item in lineElementType" :label="item.value">{{ item.label }}</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item label="开始里程">
+                    <el-input v-model="formLineEleValue.value" placeholder="请输入开始里程"/>
+                </el-form-item>
+                <el-form-item label="X">
+                    <el-input v-model="formLineEleValue.x" placeholder="请输入X"/>
+                </el-form-item>
+                <el-form-item label="Y">
+                    <el-input v-model="formLineEleValue.y" placeholder="请输入Y"/>
+                </el-form-item>
+                <el-form-item label="半径" v-if="formLineEleValue.type !== 0">
+                    <el-input v-model="formLineEleValue.r" placeholder="请输入半径"/>
+                </el-form-item>
+                <el-form-item label="结束半径" v-if="formLineEleValue.type === 3">
+                    <el-input v-model="formLineEleValue.r2" placeholder="请输入半径"/>
+                </el-form-item>
+                <el-form-item label="转向" v-if="formLineEleValue.type !== 0">
+                    <el-radio-group v-model="formLineEleValue.swing">
+                        <el-radio label="左转">左转</el-radio>
+                        <el-radio label="右转">右转</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item label="线长度">
+                    <el-input v-model="formLineEleValue.l" placeholder="请输入线长度"/>
+                </el-form-item>
+                <div class="flex">
+                    <el-form-item class="flex-1" label="方位角">
+                        <el-input v-model="formLineEleValue.du" placeholder="输入度">
+                            <template #suffix>度</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item class="flex-1 ml-4" no-label>
+                        <el-input v-model="formLineEleValue.fen" placeholder="输入分">
+                            <template #suffix>分</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item class="flex-1 ml-4" no-label>
+                        <el-input v-model="formLineEleValue.miao" placeholder="输入秒">
+                            <template #suffix>秒</template>
+                        </el-input>
+                    </el-form-item>
+                </div>
+                <el-form-item label="断链前里程" v-if="formLineEleValue.type !== 3">
+                    <el-input v-model="formLineEleValue.dlq" placeholder="请输入断链前里程"/>
+                </el-form-item>
+                <el-form-item label="断链后里程" v-if="formLineEleValue.type !== 3">
+                    <el-input v-model="formLineEleValue.dlh" placeholder="请输入断链后里程"/>
+                </el-form-item>
+                <el-form-item label="顺序">
+                    <el-input v-model="formLineEleValue.orderNum" placeholder="请输入顺序"/>
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="showLineEleModal = false">取消</el-button>
+                    <el-button size="large" @click="refreshable" v-if="formLineEleValue.id === -1 || !formLineEleValue.id">刷新</el-button>
+                    <el-button type="primary" hc-btn :loading="saveLoading" @click="saveLineEleClick">保存</el-button>
+                </div>
+            </template>
+        </el-dialog>
+        <!--里程转换坐标-->
+        <el-dialog v-model="showToModal" title="里程转换坐标" width="38rem" draggable custom-class="hc-modal-border">
+            <el-form :model="formToValue" label-width="auto" size="large">
+                <el-form-item label="里程">
+                    <el-input v-model="formToValue.value" placeholder="请输入名称"/>
+                </el-form-item>
+                <el-form-item label="偏移">
+                    <el-input v-model="formToValue.b" placeholder="请输入偏移"/>
+                </el-form-item>
+                <el-form-item label="夹角">
+                    <el-input v-model="formToValue.jj" placeholder="请输入夹角"/>
+                </el-form-item>
+                <el-form-item label="X">
+                    <div class="form-item-div">{{formToValue.x}}</div>
+                </el-form-item>
+                <el-form-item label="Y">
+                    <div class="form-item-div">{{formToValue.y}}</div>
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="showToModal = false">取消</el-button>
+                    <el-button type="primary" hc-btn @click="queryPsChange">转换</el-button>
+                </div>
+            </template>
+        </el-dialog>
+        <!--逐桩坐标弹框-->
+        <el-dialog v-model="showPileModal" title="逐桩坐标" width="62rem" draggable custom-class="hc-modal-border">
+            <el-form :model="formPileValue" label-width="auto" size="large" inline label-position="top">
+                <el-form-item label="开始桩号">
+                    <el-input v-model="formPileValue.x" placeholder="开始桩号"/>
+                </el-form-item>
+                <el-form-item label="结束桩号">
+                    <el-input v-model="formPileValue.y" placeholder="结束桩号"/>
+                </el-form-item>
+                <el-form-item label="桩距">
+                    <el-input v-model="formPileValue.value" placeholder="桩距"/>
+                </el-form-item>
+                <el-form-item label="偏距">
+                    <el-input v-model="formPileValue.b" placeholder="偏距"/>
+                </el-form-item>
+                <el-form-item label=" ">
+                    <el-button type="primary" attr-type="button" :loading="generateLoading" @click="generateClick">生成</el-button>
+                </el-form-item>
+            </el-form>
+            <div class="admin-part-data-table">
+                <el-scrollbar>
+                    <div class="hc-table-ref-box">
+                        <el-table hc :data="pileTable" stripe>
+                            <el-table-column prop="num" label="序号" width="80">
+                                <template #default="scope">
+                                    {{scope.$index + 1}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="valueStr" label="里程"/>
+                            <el-table-column prop="b" label="偏距"/>
+                            <el-table-column prop="xxStr" label="X"/>
+                            <el-table-column prop="yyStr" label="Y"/>
+                        </el-table>
+                    </div>
+                </el-scrollbar>
+            </div>
+        </el-dialog>
+        <!--导入弹框-->
+        <el-dialog v-model="showImportModal" title="导入线元" width="32rem" custom-class="hc-modal-border">
+            <div class="text-center">
+                <el-upload ref="uploadRef" :action="action" :headers="getTokenHeader()" :accept="accept" :data="addition" :limit="1" :auto-upload="false" v-model:file-list="fileList"
+                           :on-exceed="handleUploadExceed" :on-progress="handleUploadProgress" :on-success="handleUploadFinish" :on-error="handleUploadError">
+                    <template #trigger>
+                        <el-button type="primary" :loading="importLoading">选择文件</el-button>
+                    </template>
+                </el-upload>
+            </div>
+            <template #footer>
+                <div class="lr-dialog-footer">
+                    <div class="left">
+                        <el-button size="large" @click="tmportTmpClick">下载导入模板</el-button>
+                    </div>
+                    <div class="right">
+                        <el-button size="large" @click="showImportModal = false">取消</el-button>
+                        <el-button type="primary" hc-btn :disabled="fileList.length <= 0" :loading="importLoading" @click="handleImportClick">确认导入</el-button>
+                    </div>
+                </div>
+            </template>
+        </el-dialog>
     </div>
 </template>
 
 <script setup>
 import {ref, onMounted} from "vue";
-import {useAppStore} from "~src/store/index";
+import {useAppStore} from "~src/store";
 import bezierApi from '~api/gauge/bezier';
 import {getTokenHeader} from '~src/api/request/header';
-import {getArrValue, downloadBlob, formValidate} from "vue-utils-plus"
+import {isType, downloadBlob, formValidate, deepClone} from "vue-utils-plus"
+import {genFileId} from "element-plus";
 
 //初始变量
 const useAppState = useAppStore()
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
+const { isObjNull, getObjValue,  getArrValue } = isType()
 
 //渲染完成
 onMounted(() => {
@@ -125,12 +331,14 @@ const queryPartList = async () => {
     if (!error && code === 200) {
         let records = getArrValue(data)
         partData.value = records
+        AdminPartTableData.value = deepClone(records);
         if (records.length > 0 && !searchForm.value.partId) {
             searchForm.value.partId = records[0].id;
-            //getTableData()
+            getTableData()
         }
     } else {
         partData.value = []
+        AdminPartTableData.value = [];
         searchForm.value.partId = null;
     }
 }
@@ -152,24 +360,402 @@ const pageChange = ({current, size}) => {
 }
 
 //获取数据
-const getTableData = () => {
+const tableData = ref([])
+const tableLoading = ref(false)
+const getTableData = async () => {
+    tableLoading.value = true
+    const { error, code, data } = await bezierApi.queryListData(searchForm.value)
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableData.value = getArrValue(data['records'])
+        searchForm.value.total = data['total'] || 0
+    } else {
+        tableData.value = []
+        searchForm.value.total = 0
+    }
+}
+
+//编辑表格
+const handleTableEdit = (row) => {
+    const form = deepClone(row)
+    formLineEleValue.value['id'] = form['id'];
+    formLineEleValue.value['type'] = form['type'];
+    formLineEleValue.value['projectId'] = projectId.value;
+    formLineEleValue.value['contractId'] = contractId.value;
+    formLineEleValue.value['partId'] = searchForm.value.partId;
+    let mile = ['x', 'y', 'fen', 'miao', 'du', 'value', 'l',  'dlq', 'dlh', 'swing', 'r', 'r2', 'orderNum']
+    mile.forEach((key) => {
+        formLineEleValue.value[key] = form[key] + '';
+    })
+    saveLoading.value = false
+    showLineEleModal.value = true
+}
+//删除表格
+const handleTableDelete = (row) => {
+    window?.$messageBox?.alert('是否删除当前数据?', '删除提醒', {
+        showCancelButton: true,
+        confirmButtonText: '确定删除',
+        cancelButtonText: '取消',
+        callback: (action) => {
+            if (action === 'confirm') {
+                saveDelMileage(row.id)
+            }
+        }
+    })
+}
+//确认删除
+const saveDelMileage = async (rid) => {
+    const {error, code} = await bezierApi.saveDelMileage({id: rid}, false)
+    //判断状态
+    if (!error && code === 200) {
+        window?.$message?.success('删除成功')
+        getTableData()
+    } else {
+        window?.$message?.error('删除失败')
+    }
+}
+
+//线元类型
+const showLineEleModal = ref(false)
+const formLineEleValue = ref({type: 0})
+const lineElementType = ref([
+    {value: 0, label: "直线段"},
+    {value: 1, label: "圆曲线"},
+    {value: 2, label: "入缓和曲线"},
+    {value: 3, label: "出缓和曲线"},
+    {value: 4, label: "不完整缓和曲线"},
+])
+//获取类型名称
+const getTypeName = (val) => {
+    if (val !== -1 || val >= 0) {
+        return lineElementType.value[val].label || '';
+    } else {
+        return '-';
+    }
+}
+//添加线元
+const addLineEleModal = () => {
+    saveLoading.value = false
+    showLineEleModal.value = true
+    getNextMileagexy()
+}
+//刷新
+const refreshable = () => {
+    getNextMileagexy({
+        orderNum: formLineEleValue.value['orderNum']
+    })
+}
+//保存
+const saveLoading = ref(false)
+const saveLineEleClick = async () => {
+    let form = formLineEleValue.value
+    form.partId = searchForm.value.partId;
+    if (form.id === -1 || !form.id) {
+        saveLoading.value = true
+        const { error, code } = await bezierApi.saveAddMileage(form)
+        saveLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('保存成功')
+            showLineEleModal.value = false
+            getTableData()
+        }
+    } else {
+        saveLoading.value = true
+        const { error, code } = await bezierApi.saveUpdateMileage(form)
+        saveLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('保存成功')
+            showLineEleModal.value = false
+            getTableData()
+        }
+    }
+}
+//获取数据
+const getNextMileagexy = async (obj = {}) => {
+    const { error, code, data } = await bezierApi.getNextMileagexy({
+        ...obj,
+        projectId: projectId.value,
+        contractId: contractId.value
+    })
+    if (!error && code === 200) {
+        const res = getObjValue(data)
+        if (!isObjNull(res)) {
+            let mile = ['x', 'y', 'fen', 'miao', 'du', 'value', 'l',  'dlq', 'dlh', 'swing', 'r', 'r2', 'orderNum']
+            mile.forEach((key) => {
+                formLineEleValue.value[key] = res[key] + '';
+            })
+            formLineEleValue.value['type'] = res['type'];
+            formLineEleValue.value['projectId'] = projectId.value;
+            formLineEleValue.value['contractId'] = contractId.value;
+            formLineEleValue.value['partId'] = searchForm.value.partId;
+        } else {
+            formLineEleValue.value = {type: 0}
+            formLineEleValue.value['projectId'] = projectId.value;
+            formLineEleValue.value['contractId'] = contractId.value;
+            formLineEleValue.value['partId'] = searchForm.value.partId;
+        }
+    }
+}
+
+//转换坐标
+const showToModal = ref(false)
+const formToValue = ref({value: '', b: '0', jj: '90', x: '', y: ''})
+const showToModalClick = () => {
+    formToValue.value = {value: '', b: '0', jj: '90', x: '', y: ''}
+    showToModal.value = true
+}
+//转换坐标
+const queryPsChange = async () => {
+    const {error, code, data} = await bezierApi.queryPsChange({
+        ...formToValue.value,
+        projectId: projectId.value,
+        partId: searchForm.value.partId
+    })
+    //判断状态
+    if (!error && code === 200) {
+        const res = getObjValue(data)
+        formToValue.value['x'] = res?.x + '';
+        formToValue.value['y'] = res?.y + '';
+        window?.$message?.success('转换成功')
+    }
+}
+
+//逐桩坐标
+const showPileModal = ref(false)
+const formPileValue = ref({})
+const pileModalClick = () => {
+    formPileValue.value = {x: '0', y: '0', value: '0', b: '0'}
+    pileTable.value = []
+    generateLoading.value = false
+    showPileModal.value = true
+}
+//确认生成
+const generateLoading = ref(false)
+const pileTable = ref([])
+const generateClick = async () => {
+    generateLoading.value = true
+    const {error, code, data} = await bezierApi.getZzList({
+        ...formPileValue.value,
+        projectId: projectId.value,
+        partId: searchForm.value.partId
+    })
+    //判断状态
+    generateLoading.value = false
+    if (!error && code === 200) {
+        pileTable.value = getArrValue(data);
+    } else {
+        pileTable.value = [];
+    }
+}
+
+//导入配置
+const showImportModal = ref(false)
+const importLoading = ref(false)
+
+//上传配置
+const uploadRef = ref(null)
+const addition = ref({})
+const fileList = ref([])
+const action = '/api/blade-business/mileage/import';
+const accept = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel';
+
+//导入
+const importModalClick = () => {
+    addition.value = {
+        projectId: projectId.value,
+        contractId: contractId.value,
+        partId: searchForm.value.partId
+    }
+    importLoading.value = false
+    showImportModal.value = true
+}
+
+//下载导入模板
+const tmportTmpClick = () => {
+    window.open('https://bladex-test-info.oss-cn-chengdu.aliyuncs.com//upload/20220614/a8bb45b57e409ff6bd5a5aad4bc7b22e.xlsx','_blank')
+}
+//上传一个文件时,重置
+const handleUploadExceed = (files) => {
+    uploadRef.value?.clearFiles()
+    const file = files[0]
+    file.uid = genFileId()
+    uploadRef.value?.handleStart(file)
+}
 
+//确认导入
+const handleImportClick = () => {
+    uploadRef.value?.submit()
+}
+//上传中
+const handleUploadProgress = () => {
+    importLoading.value = true
+}
+//上传完成
+const handleUploadFinish = () => {
+    importLoading.value = false
+    showImportModal.value = false
+    window?.$message?.success('导入成功')
+    uploadRef.value?.clearFiles()
+    getTableData()
+}
+//上传失败
+const handleUploadError = () => {
+    importLoading.value = false
+    window?.$message?.error('导入失败')
+}
+
+//导出
+const exportModalClick = () => {
+    window?.$messageBox?.alert('请确认当前查询条件,系统将以当前筛选条件导出数据', '导出数据', {
+        showCancelButton: true,
+        confirmButtonText: '确定导出',
+        cancelButtonText: '取消',
+        callback: (action) => {
+            if (action === 'confirm') {
+                getExportExcel()
+            }
+        }
+    })
+}
+//确定导出
+const downloadLoading = ref(false)
+const getExportExcel = async () => {
+    //批量下载
+    downloadLoading.value = true
+    const { error, disposition, res } = await bezierApi.getExportExcel({
+        projectId: projectId.value,
+        partId: searchForm.value.partId,
+        partNo: ''
+    })
+    //处理数据
+    downloadLoading.value = false
+    if (!error) {
+        if (disposition) {
+            downloadBlob(res,disposition)
+        } else {
+            window.$message?.error('数据异常')
+        }
+    }
+}
+
+
+//片段管理表单
+const partFormRef = ref(null)
+const partForm = ref({name: '', prefix: ''})
+const partRules = {
+    name: {
+        required: true,
+        trigger: "blur",
+        message: "请输入名称"
+    },
+    prefix: {
+        required: true,
+        validator: (rule, value, callback) => {
+            const reg = /^[A-Z]+$/
+            if (!value) {
+                callback(new Error('请输入桩号前缀'))
+            } else if (!reg.test(value)) {
+                callback(new Error('只允许输入大写的英文字母'))
+            }
+            callback()
+        },
+        trigger: "blur",
+    }
 }
 
-//管理片段弹窗
+//管理片段
 const showAdminPartModal = ref(false)
 const AdminPartTableData = ref([])
 const AdminPartClick = () => {
+    AdminPartTableData.value = deepClone(partData.value);
+    showAdminPartModal.value = true
+}
+
+//新增片段弹框
+const showAddPartModal = ref(false)
+const AddPartClick = () => {
+    partForm.value = {name: '', prefix: ''}
+    savePartLoading.value = false
+    showAddPartModal.value = true
+}
+//新增保存
+const savePartLoading = ref(false)
+const savePartInfo = async () => {
+    const validate = await formValidate(partFormRef.value)
+    if (validate) {
+        savePartLoading.value = true
+        const { error, code } = await bezierApi.savePartAdd({
+            ...partForm.value,
+            projectId: projectId.value,
+            contractId: contractId.value
+        })
+        savePartLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('新增成功')
+            showAddPartModal.value = false
+            queryPartList()
+        }
+    }
+}
 
+//新增
+const AddAdminPart = () => {
+    AdminPartTableData.value.push({
+        id: '', name: '', prefix: '', isEdit: true
+    })
 }
 //编辑
-const handleAdminPartdit = () => {
+const handleAdminPartEdit = (row) => {
+    row.isEdit = true
+}
 
+//保存
+const handleAdminPartSave = async (row) => {
+    const reg = /^[A-Z]+$/
+    if (!row.name) {
+        window?.$message?.warning('请输入名称')
+    } else if (!row.prefix) {
+        window?.$message?.warning('请输入桩号前缀')
+    } else if (!reg.test(row.prefix)) {
+        window?.$message?.warning('桩号前缀,只允许输入大写的英文字母')
+    } else if (row.id) {
+        const { error, code } = await bezierApi.savePartUpdate({
+            ...row,
+            projectId: projectId.value,
+            contractId: contractId.value
+        })
+        if (!error && code === 200) {
+            window?.$message?.success('保存成功')
+            row.isEdit = false
+            queryPartList()
+        }
+    } else if (!row.id) {
+        const { error, code } = await bezierApi.savePartAdd({
+            ...row,
+            projectId: projectId.value,
+            contractId: contractId.value
+        })
+        if (!error && code === 200) {
+            window?.$message?.success('保存成功')
+            row.isEdit = false
+            queryPartList()
+        }
+    }
 }
 
 //删除
-const handleAdminPartDelete = () => {
-
+const handleAdminPartDelete = async (row, index) => {
+    if (!!row.id) {
+        const { error, code } = await bezierApi.delPartData({
+            ids: row.id
+        })
+        if (!error && code === 200) {
+            window?.$message?.success('删除成功')
+            queryPartList()
+        }
+    } else {
+        AdminPartTableData.value.splice(index, 1)
+    }
 }
 
 </script>

+ 0 - 787
src/views/gauge/bezier_a.vue

@@ -1,787 +0,0 @@
-<template>
-    <n-divider dashed title-placement="left">平曲线</n-divider>
-    <div class="hc-layout-box">
-        <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
-            <template #header>
-                <div class="hc-card-header flex items-center">
-                    <div class="w-60 mr-4">
-                        <n-select label-field="name" value-field="id" v-model:value="searchForm.partId" :options="partData" placeholder="片段查询" @update:value="searchChange" clearable/>
-                    </div>
-                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_add_part?.textInfo" v-if="btn_add_part">
-                        <template #trigger>
-                            <span class="ml-3 icon-btn" @click="AddPartClick">
-                                <i class="cicon-add-round-o"/>
-                            </span>
-                        </template>
-                        <span>{{btn_add_part?.textInfo}}</span>
-                    </n-popover>
-                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_admin_part?.textInfo" v-if="btn_admin_part">
-                        <template #trigger>
-                            <span class="ml-3 icon-btn" @click="AdminPartClick">
-                                <i class="cicon-set-list"/>
-                            </span>
-                        </template>
-                        <span>{{btn_admin_part?.textInfo}}</span>
-                    </n-popover>
-                </div>
-            </template>
-            <template #header-extra>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_add?.textInfo" v-if="btn_add">
-                    <template #trigger>
-                        <n-button type="primary" strong secondary class="px-5" @click="addLineEleModal">添加线元</n-button>
-                    </template>
-                    <span>{{btn_add?.textInfo}}</span>
-                </n-popover>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_to?.textInfo" v-if="btn_to">
-                    <template #trigger>
-                        <n-button type="primary" strong secondary class="px-5 ml-3" @click="showToModalClick">转换坐标</n-button>
-                    </template>
-                    <span>{{btn_to?.textInfo}}</span>
-                </n-popover>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_import?.textInfo" v-if="btn_import">
-                    <template #trigger>
-                        <n-button type="primary" strong secondary class="px-5 ml-3" @click="importModalClick">导入线元</n-button>
-                    </template>
-                    <span>{{btn_import?.textInfo}}</span>
-                </n-popover>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_pile?.textInfo" v-if="btn_pile">
-                    <template #trigger>
-                        <n-button type="primary" strong secondary class="px-5 ml-3" @click="pileModalClick">逐桩坐标</n-button>
-                    </template>
-                    <span>{{btn_pile?.textInfo}}</span>
-                </n-popover>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_export?.textInfo" v-if="btn_export">
-                    <template #trigger>
-                        <n-button type="primary" strong secondary class="px-5 ml-3" @click="exportModalClick">导出</n-button>
-                    </template>
-                    <span>{{btn_export?.textInfo}}</span>
-                </n-popover>
-            </template>
-            <n-data-table :columns="tableColumns" :data="tableData" :pagination="false" :row-key="row => row.name" :loading="tableLoading" :single-line="false" striped/>
-            <template #action>
-                <HcPage :pages="searchForm" @change="pageChange"/>
-            </template>
-        </n-card>
-    </div>
-    <!--新增片段弹框-->
-    <n-modal v-model:show="showAddPartModal">
-        <n-card class="w-606" title="新增片段" :segmented="{content: true}">
-            <n-form ref="formAddPartRef" :model="formAddPartValue" :rules="rulesAddPart" label-placement="left" label-width="auto" size="large">
-                <n-form-item label="名称" path="name">
-                    <n-input class="flex-1" v-model:value="formAddPartValue.name" placeholder="请输入名称"/>
-                </n-form-item>
-                <n-form-item label="桩号前缀" path="prefix">
-                    <n-input class="flex-1" v-model:value="formAddPartValue.prefix" placeholder="只允许输入大写的英文字母"/>
-                </n-form-item>
-            </n-form>
-            <template #action>
-                <div class="text-center">
-                    <n-button class="px-5" @click="showAddPartModal = false">取消</n-button>
-                    <n-button type="primary" class="px-5 ml-6" :loading="savePartLoading" @click="savePartInfo(formAddPartValue, true)">保存</n-button>
-                </div>
-            </template>
-        </n-card>
-    </n-modal>
-    <!--管理片段弹框-->
-    <n-modal v-model:show="showAdminPartModal">
-        <n-card class="w-750" title="管理片段" :segmented="{content: true}">
-            <div class="admin-part-data-table">
-                <n-data-table :key="(row) => row.id" :columns="AdminPartColumns" :data="AdminPartTableData" :single-line="false" striped/>
-            </div>
-            <template #action>
-                <div class="text-center">
-                    <n-button class="px-5" @click="showAdminPartModal = false">取消</n-button>
-                    <n-button type="primary" class="px-5 ml-6" @click="AddAdminPart">新增</n-button>
-                </div>
-            </template>
-        </n-card>
-    </n-modal>
-
-    <!--添加/编辑线元弹框-->
-    <n-modal v-model:show="showLineEleModal">
-        <n-card class="w-750" :title="(formLineEleValue.id == -1 || !formLineEleValue.id)?'添加线元':'编辑线元'" :segmented="{content: true}">
-            <n-form :model="formLineEleValue" label-placement="left" label-width="auto" size="large">
-                <n-form-item label="类型">
-                    <n-radio-group class="flex-1" v-model:value="formLineEleValue.type" name="radiogroup">
-                        <n-space>
-                            <n-radio v-for="item in lineElementType" :key="item.value" :value="item.value">{{ item.label }}</n-radio>
-                        </n-space>
-                    </n-radio-group>
-                </n-form-item>
-                <n-form-item label="开始里程">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.value" placeholder="请输入开始里程"/>
-                </n-form-item>
-                <n-form-item label="X">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.x" placeholder="请输入X"/>
-                </n-form-item>
-                <n-form-item label="Y">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.y" placeholder="请输入Y"/>
-                </n-form-item>
-                <n-form-item label="半径" v-if="formLineEleValue.type != 0">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.r" placeholder="请输入半径"/>
-                </n-form-item>
-                <n-form-item label="结束半径" v-if="formLineEleValue.type == 3">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.r2" placeholder="请输入半径"/>
-                </n-form-item>
-                <n-form-item label="转向" v-if="formLineEleValue.type != 0">
-                    <n-radio-group class="flex-1" v-model:value="formLineEleValue.swing" name="radiogroup">
-                        <n-space>
-                            <n-radio value="左转">左转</n-radio>
-                            <n-radio value="右转">右转</n-radio>
-                        </n-space>
-                    </n-radio-group>
-                </n-form-item>
-                <n-form-item label="线长度">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.l" placeholder="请输入线长度"/>
-                </n-form-item>
-                <div class="flex">
-                    <n-form-item class="flex-1" label="方位角">
-                        <n-input v-model:value="formLineEleValue.du" placeholder="输入度">
-                            <template #suffix>度</template>
-                        </n-input>
-                    </n-form-item>
-                    <n-form-item class="flex-1 ml-4">
-                        <n-input v-model:value="formLineEleValue.fen" placeholder="输入分">
-                            <template #suffix>分</template>
-                        </n-input>
-                    </n-form-item>
-                    <n-form-item class="flex-1 ml-4">
-                        <n-input v-model:value="formLineEleValue.miao" placeholder="输入秒">
-                            <template #suffix>秒</template>
-                        </n-input>
-                    </n-form-item>
-                </div>
-                <n-form-item label="断链前里程" v-if="formLineEleValue.type != 3">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.dlq" placeholder="请输入断链前里程"/>
-                </n-form-item>
-                <n-form-item label="断链后里程" v-if="formLineEleValue.type != 3">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.dlh" placeholder="请输入断链后里程"/>
-                </n-form-item>
-                <n-form-item label="顺序">
-                    <n-input class="flex-1" v-model:value="formLineEleValue.orderNum" placeholder="请输入顺序"/>
-                </n-form-item>
-            </n-form>
-            <template #action>
-                <div class="text-center">
-                    <n-button class="px-5" @click="showLineEleModal = false">取消</n-button>
-                    <n-button type="primary" strong secondary class="px-5 ml-6" @click="refreshable" v-if="formLineEleValue.id == -1 || !formLineEleValue.id">刷新</n-button>
-                    <n-button type="primary" class="px-5 ml-6" :loading="saveLoading" @click="saveClick">保存</n-button>
-                </div>
-            </template>
-        </n-card>
-    </n-modal>
-    <!--里程转换坐标-->
-    <n-modal v-model:show="showToModal">
-        <n-card class="w-606" title="里程转换坐标" :segmented="{content: true}">
-            <n-form :model="formToValue" label-placement="left" label-width="auto" size="large">
-                <n-form-item label="里程">
-                    <n-input class="flex-1" v-model:value="formToValue.value" placeholder="请输入里程"/>
-                </n-form-item>
-                <n-form-item label="偏移">
-                    <n-input class="flex-1" v-model:value="formToValue.b" placeholder="请输入偏移"/>
-                </n-form-item>
-                <n-form-item label="夹角">
-                    <n-input class="flex-1" v-model:value="formToValue.jj" placeholder="请输入夹角"/>
-                </n-form-item>
-                <n-form-item label="X">{{formToValue.x}}</n-form-item>
-                <n-form-item label="Y">{{formToValue.y}}</n-form-item>
-            </n-form>
-            <template #action>
-                <div class="text-center">
-                    <n-button class="px-5" @click="showToModal = false">取消</n-button>
-                    <n-button type="primary" class="px-5 ml-6" @click="queryPsChange">转换</n-button>
-                </div>
-            </template>
-        </n-card>
-    </n-modal>
-    <!--导入 弹框-->
-    <n-modal v-model:show="showImportModal">
-        <n-card class="w-414" title="导入线元" :segmented="{content: true}">
-            <template #header-extra>
-                <a href="https://bladex-test-info.oss-cn-chengdu.aliyuncs.com//upload/20220614/a8bb45b57e409ff6bd5a5aad4bc7b22e.xlsx" target="_blank" class="text-link">下载导入模板</a>
-            </template>
-            <div class="text-center">
-                <n-upload ref="uploadRef" :action="action" :headers="getTokenHeader()" :data="upData" :max="1" :accept="accept" :default-upload="false" multiple @change="handleUploadChange" @finish="uploadFinish">
-                    <n-button type="primary" class="px-4">选择文件</n-button>
-                </n-upload>
-            </div>
-            <template #action>
-                <div class="text-center">
-                    <n-button class="px-4" @click="showImportModal = false">取消</n-button>
-                    <n-button type="primary" :disabled="!fileListLength" class="px-4 ml-6" :loading="importLoading" @click="handleImportClick">确认导入</n-button>
-                </div>
-            </template>
-        </n-card>
-    </n-modal>
-    <!--逐桩坐标弹框-->
-    <n-modal v-model:show="showPileModal">
-        <n-card class="w-990" title="逐桩坐标" :segmented="{content: true}">
-            <n-form :model="formPileValue" inline label-width="auto">
-                <n-form-item label="开始桩号">
-                    <n-input v-model:value="formPileValue.x" placeholder="开始桩号" />
-                </n-form-item>
-                <n-form-item label="结束桩号">
-                    <n-input v-model:value="formPileValue.y" placeholder="结束桩号" />
-                </n-form-item>
-                <n-form-item label="桩距">
-                    <n-input v-model:value="formPileValue.value" placeholder="桩距" />
-                </n-form-item>
-                <n-form-item label="偏距">
-                    <n-input v-model:value="formPileValue.b" placeholder="偏距" />
-                </n-form-item>
-                <n-form-item>
-                    <n-button attr-type="button" type="primary" class="px-4" :loading="generateLoading" @click="generateClick">生成</n-button>
-                </n-form-item>
-            </n-form>
-            <div class="admin-part-data-table">
-                <n-data-table :key="(row) => row.key" :columns="pileColumns" :data="pileTable" :single-line="false" striped/>
-            </div>
-            <template #action>
-                <div class="text-center">
-                    <n-button class="px-5" @click="showPileModal = false">关闭</n-button>
-                </div>
-            </template>
-        </n-card>
-    </n-modal>
-</template>
-
-<script setup>
-import {h, onMounted, ref, watch} from "vue";
-import {useAppStore} from "~src/store/index";
-import bezier from '~api/gauge/bezier';
-import HcPage from "~com/plugins/naive/HcPage.vue"
-import {getTokenHeader} from '~src/api/request/header';
-import {download} from '~src/utils/lib/tools';
-//import {renderTableEditDelButton,renderTableEditInput, renderTableEditInputButton} from "~src/plugins/renderele";
-
-//初始变量
-const useAppState = useAppStore()
-const projectId = ref(useAppState.getProjectId);
-const contractId = ref(useAppState.getContractId);
-//按钮气泡开关
-const bubbleVal = ref(useAppState.getBubble);
-
-//监听
-watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getBubble,
-], ([UserProjectId,UserContractId,Bubble]) => {
-    //项目合同数据
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    //按钮气泡开关
-    bubbleVal.value = Bubble
-})
-
-//获取气泡数据
-const getButtonsVal = (value) => {
-    return useAppState.getButtonsVal(value)
-}
-
-//气泡数据
-const btn_add_part = ref(getButtonsVal('gauge-bezier-add-part'))
-const btn_admin_part = ref(getButtonsVal('gauge-bezier-admin-part'))
-
-const btn_add = ref(getButtonsVal('gauge-bezier-add'))
-const btn_to = ref(getButtonsVal('gauge-bezier-to'))
-const btn_import = ref(getButtonsVal('gauge-bezier-import'))
-const btn_pile = ref(getButtonsVal('gauge-bezier-pile'))
-const btn_export = ref(getButtonsVal('gauge-bezier-export'))
-const btn_edit = ref(getButtonsVal('gauge-bezier-edit'))
-const btn_del = ref(getButtonsVal('gauge-bezier-del'))
-
-//片段查询
-const partData = ref([])
-//搜索表单
-const searchForm = ref({partId: '', current: 1, size: 20, total: 0})
-const lineElementType = ref([
-    {value: 0, label: "直线段"},
-    {value: 1, label: "圆曲线"},
-    {value: 2, label: "入缓和曲线"},
-    {value: 3, label: "出缓和曲线"},
-    {value: 4, label: "不完整缓和曲线"},
-])
-
-//获取类型名称
-const GetTypeName = (val) => {
-    if (val != -1 || val >= 0) {
-        return lineElementType.value[val].label || '';
-    } else {
-        return '-';
-    }
-}
-
-//渲染完成
-onMounted(() => {
-    queryPartList().then()
-})
-
-async function queryPartList() {
-    const partList = await bezier.queryPartList({
-        projectId: projectId.value,
-        contractId: contractId.value
-    })
-    let partListData = partList?.data?.data || [];
-    partData.value = partListData;
-    if (partListData.length > 0 && !searchForm.value.partId) {
-        searchForm.value.partId = partListData[0].id;
-        getTableData()
-    }
-}
-
-//导线点的 表格表头
-const tableLoading = ref(false)
-const createColumns = ({edit,del}) => {
-    return [
-        {title: '序号', key: 'num', width: 80, align: 'center',
-            render(_, index) {
-                return index + 1
-            }
-        },
-        {title: '里程', key: 'name',
-            render(row) {
-                return `${row.valueStr}~${row.valueEndStr}`
-            }
-        },
-        {title: '排序', key: 'orderNum'},
-        {title: '长度', key: 'l'},
-        {title: '方位角', key: 'angle'},
-        {title: '类型', key: 'type',
-            render(row) {
-                return GetTypeName(row.type)
-            }
-        },
-        {title: '转向', key: 'swing'},
-        {title: 'X', key: 'xxStr'},
-        {title: 'Y', key: 'yyStr'},
-        {title: '半径', key: 'r'},
-        {title: "操作", key: "actions", width: 160, align: 'center',
-            render(row) {
-                /*return renderTableEditDelButton({
-                    bubble: bubbleVal.value,
-                    btn_edit: btn_edit.value,
-                    btn_del: btn_del.value,
-                    edit_event: edit,
-                    del_event: del,
-                    row:row
-                })*/
-            }
-        }
-    ];
-};
-const tableColumns = createColumns({
-    edit(row) {
-        const form = JSON.parse(JSON.stringify(row))
-        formLineEleValue.value['id'] = form.id;
-        formLineEleValue.value['type'] = form['type'];
-        formLineEleValue.value['projectId'] = projectId.value;
-        formLineEleValue.value['contractId'] = contractId.value;
-        formLineEleValue.value['partId'] = searchForm.value.partId;
-        let mile = ['x', 'y', 'fen', 'miao', 'du', 'value', 'l',  'dlq', 'dlh', 'swing', 'r', 'r2', 'orderNum']
-        mile.forEach((key) => {
-            formLineEleValue.value[key] = form[key] + '';
-        })
-        showLineEleModal.value = true
-    },
-    del(row) {
-        bezier.saveDelMileage({
-            id: row.id
-        }).then(({data}) => {
-            if (data.code === 200) {
-                window?.$message?.success('删除成功')
-                getTableData()
-            } else {
-                window?.$message?.error('删除失败')
-            }
-        })
-    },
-})
-const tableData = ref([]);
-
-//重新搜索数据
-const searchChange = (res) => {
-    searchForm.value.current = 1
-    getTableData()
-}
-//分页被点击
-const pageChange = (res) => {
-    searchForm.value.current = res.current;
-    searchForm.value.size = res.size;
-    getTableData()
-}
-//获取数据
-const getTableData = () => {
-    tableLoading.value = true
-    bezier.queryListData(searchForm.value).then(({data}) => {
-        let res = data['data'] || {}
-        tableData.value = res['records'] || []
-        searchForm.value.total = res.total || 0
-        tableLoading.value = false
-    }).catch(() => {
-        tableLoading.value = false
-    })
-}
-
-//新增片段弹框
-const showAddPartModal = ref(false)
-const formAddPartRef = ref(null)
-const formAddPartValue = ref({name: '', prefix: ''})
-const rulesAddPart = {
-    name: {
-        required: true,
-        trigger: ["blur", "input"],
-        message: "请输入名称"
-    },
-    prefix: {
-        required: true,
-        validator(rule, value) {
-            const reg = /^[A-Z]+$/
-            if (!value) {
-                return new Error("请输入桩号前缀");
-            } else if (!reg.test(value)) {
-                return new Error("只允许输入大写的英文字母");
-            }
-            return true;
-        },
-        trigger: ["blur", "input"],
-    }
-}
-//添加片段按钮
-const AddPartClick = () => {
-    formAddPartValue.value.name = ''
-    formAddPartValue.value.prefix = ''
-    showAddPartModal.value = true
-}
-//管理片段弹窗
-const showAdminPartModal = ref(false)
-const AdminPartTableData = ref([])
-const AdminPartColumns = [
-    {
-        title: '片段名称',
-        key: 'name',
-        render (row) {
-            /*return h(renderTableEditInput, {
-                value: row.name,
-                isEdit: row.isEdit,
-                onUpdateValue (val) {
-                    row.name = val
-                }
-            })*/
-        }
-    },
-    {
-        title: '桩号前缀',
-        key: 'prefix',
-        render (row) {
-            /*return h(renderTableEditInput, {
-                value: row.prefix,
-                isEdit: row.isEdit,
-                onUpdateValue (val) {
-                    row.prefix = val
-                }
-            })*/
-        }
-    },
-    {title: "操作", key: "actions", width: 160, align: 'center',
-        render(row,index) {
-            /*return h(renderTableEditInputButton, {
-                row: row,
-                onSave (res) {
-                    const reg = /^[A-Z]+$/
-                    if (!res.name) {
-                        row.isEdit = true
-                        window?.$message?.warning('请输入片段名称')
-                    } else if (!res.prefix) {
-                        row.isEdit = true
-                        window?.$message?.warning('请输入桩号前缀')
-                    } else if (!reg.test(res.prefix)) {
-                        row.isEdit = true
-                        window?.$message?.warning('桩号前缀只允许输入大写的英文字母')
-                    } else {
-                        row.isEdit = false
-                        savePartInfo(row)
-                    }
-                },
-                onDel (res) {
-                    if (!!row.id) {
-                        bezier.delPartData({
-                            ids: row.id
-                        }).then(({data}) => {
-                            if (data.code === 200) {
-                                queryPartList().then()
-                                AdminPartTableData.value.splice(index, 1)
-                                window?.$message?.success('删除成功')
-                            } else {
-                                window?.$message?.error('删除失败')
-                            }
-                        })
-                    } else {
-                        AdminPartTableData.value.splice(index, 1)
-                    }
-                }
-            })*/
-        }
-    }
-];
-//保存片段数据
-const savePartLoading = ref(false)
-const savePartInfo = (row,modal = false) => {
-    if (!!row.id) {
-        savePartLoading.value = true
-        bezier.savePartUpdate(row).then(({data}) => {
-            savePartLoading.value = false
-            if (data.code === 200) {
-                row.isEdit = false
-                queryPartList().then()
-                window?.$message?.success('更新成功')
-                if (modal) showAddPartModal.value = false
-            } else {
-                row.isEdit = true
-                window?.$message?.error('更新失败')
-            }
-        }).catch(() => {
-            savePartLoading.value = false
-        })
-    } else {
-        savePartLoading.value = true
-        row.projectId = projectId.value;
-        row.contractId = contractId.value;
-        bezier.savePartAdd(row).then(({data}) => {
-            savePartLoading.value = false
-            if (data.code === 200) {
-                row = data.data
-                row.isEdit = false
-                queryPartList().then()
-                window?.$message?.success('新增成功')
-                if (modal) showAddPartModal.value = false
-            } else {
-                row.isEdit = true
-                window?.$message?.error('新增失败')
-            }
-        }).catch(() => {
-            savePartLoading.value = false
-        })
-    }
-}
-const AdminPartClick = () => {
-    AdminPartTableData.value = JSON.parse(JSON.stringify(partData.value));
-    showAdminPartModal.value = true
-}
-const AddAdminPart = () => {
-    AdminPartTableData.value.push({
-        id: '', name: '', prefix: '',
-        isEdit: true
-    })
-}
-
-//线元类型
-const showLineEleModal = ref(false)
-const formLineEleValue = ref({type: 0})
-//添加线元弹窗
-const addLineEleModal = () => {
-    showLineEleModal.value = true
-    getNextMileagexy()
-}
-//刷新
-const refreshable = () => {
-    getNextMileagexy({
-        orderNum: formLineEleValue.value['orderNum']
-    })
-}
-
-//获取初始信息
-const getNextMileagexy = (obj = {}) => {
-    bezier.getNextMileagexy({
-        projectId: projectId.value,
-        partId: searchForm.value.partId,
-        ...obj
-    }).then(({data}) => {
-        if(!!data) {
-            let mile = ['x', 'y', 'fen', 'miao', 'du', 'value', 'l',  'dlq', 'dlh', 'swing', 'r', 'r2', 'orderNum']
-            mile.forEach((key) => {
-                formLineEleValue.value[key] = data[key] + '';
-            })
-            formLineEleValue.value['type'] = data['type'];
-            formLineEleValue.value['projectId'] = projectId.value;
-            formLineEleValue.value['contractId'] = contractId.value;
-            formLineEleValue.value['partId'] = searchForm.value.partId;
-        } else {
-            formLineEleValue.value = {type: 0}
-            formLineEleValue.value['projectId'] = projectId.value;
-            formLineEleValue.value['contractId'] = contractId.value;
-            formLineEleValue.value['partId'] = searchForm.value.partId;
-        }
-    })
-}
-
-//保存线元数据
-const saveLoading = ref(false)
-const saveClick = () => {
-    let form = formLineEleValue.value || {};
-    form.partId = searchForm.value.partId;
-    if (form.id === -1 || !form.id) {
-        saveLoading.value = true
-        bezier.saveAddMileage(form).then(({data}) => {
-            saveLoading.value = false
-            if (data.code === 200) {
-                window?.$message?.success('保存成功')
-                showLineEleModal.value = false
-                getTableData()
-            } else {
-                window?.$message?.error('保存失败')
-            }
-        }).catch(() => {
-            saveLoading.value = false
-        })
-    } else {
-        saveLoading.value = true
-        bezier.saveUpdateMileage(form).then(({data}) => {
-            saveLoading.value = false
-            if (data.code === 200) {
-                window?.$message?.success('保存成功')
-                showLineEleModal.value = false
-                getTableData()
-            } else {
-                window?.$message?.error('保存失败')
-            }
-        }).catch(() => {
-            saveLoading.value = false
-        })
-    }
-}
-
-//里程转换坐标
-const showToModal = ref(false)
-const formToValue = ref({value: '', b: '0', jj: '90', x: '', y: ''})
-const showToModalClick = () => {
-    formToValue.value = {value: '', b: '0', jj: '90', x: '', y: ''}
-    showToModal.value = true
-}
-//转换坐标
-const queryPsChange = () => {
-    bezier.queryPsChange({
-        projectId: projectId.value,
-        partId: searchForm.value.partId,
-        value: formToValue.value.value,
-        b: formToValue.value.b,
-        jj: formToValue.value.jj
-    }).then(({data}) => {
-        if (data.code === 200) {
-            formToValue.value['x'] = data?.data?.x + '';
-            formToValue.value['y'] = data?.data?.y + '';
-            window?.$message?.success('转换成功')
-        } else {
-            window?.$message?.error('转换失败')
-        }
-    })
-}
-
-//导入弹窗
-const showImportModal = ref(false)
-const fileListLength = ref(0);
-const uploadRef = ref(null);
-
-//上传组件参数
-const action = '/api/blade-business/mileage/import';
-const accept = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel';
-const upData = ref({
-    projectId: projectId.value,
-    contractId: contractId.value,
-    partId: searchForm.value.partId
-})
-
-const importLoading = ref(false)
-const importModalClick = () => {
-    showImportModal.value = true
-    upData.value = {
-        projectId: projectId.value,
-        contractId: contractId.value,
-        partId: searchForm.value.partId
-    }
-}
-const handleUploadChange = (options) => {
-    fileListLength.value = options.fileList.length;
-}
-const handleImportClick = () => {
-    importLoading.value = true
-    uploadRef.value?.submit();
-}
-//上传完成
-const uploadFinish = ({event}) => {
-    importLoading.value = false
-    let res = JSON.parse(event?.target?.response);
-    if (res.code === 200) {
-        window?.$message?.success('导入成功')
-        showImportModal.value = false
-        getTableData()
-    } else {
-        window?.$message?.error('导入失败')
-    }
-}
-
-//逐桩坐标
-const showPileModal = ref(false)
-const formPileValue = ref({x: '0', y: '0', value: '0', b: '0'})
-const pileColumns = [
-    {title: '序号', key: 'key', width: 80, align: 'center',
-        render(_, index) {
-            return index + 1
-        }
-    },
-    {title: '里程', key: 'valueStr'},
-    {title: '偏距', key: 'b'},
-    {title: 'X', key: 'xxStr'},
-    {title: 'Y', key: 'yyStr'}
-];
-const pileTable = ref([]);
-const pileModalClick = () => {
-    formPileValue.value = {
-        projectId: projectId.value,
-        partId: searchForm.value.partId,
-        x: '0',
-        y: '0',
-        value: '0',
-        b: '0'
-    }
-    showPileModal.value = true
-}
-//生成
-const generateLoading = ref(false)
-const generateClick = () => {
-    generateLoading.value = true
-    bezier.getZzList(formPileValue.value).then(({data}) => {
-        generateLoading.value = false
-        if (data.code === 200) {
-            pileTable.value = data.data;
-        } else {
-            window?.$message?.error('生成失败')
-        }
-    }).catch(() => {
-        generateLoading.value = false
-    })
-}
-
-//导出弹窗
-const exportModalClick  = () => {
-    window?.$dialog?.warning({
-        title: "导出数据",
-        content: "请确认当前查询条件,系统将以当前筛选条件导出数据",
-        positiveText: "确定导出",
-        negativeText: "取消",
-        onPositiveClick: () => {
-            bezier.getExportExcel({
-                projectId: projectId.value,
-                partId: searchForm.value.partId,
-                partNo: ''
-            }).then(res => {
-                download(res)
-            })
-        }
-    });
-}
-</script>
-
-<style lang="scss" scoped>
-@import '../../styles/gauge/bezier.scss';
-</style>

+ 97 - 0
src/views/other-file/components/HcTreeData.vue

@@ -0,0 +1,97 @@
+<template>
+    <ElTree class="hc-tree-node" :props="ElTreeProps" :data="datas" highlight-current accordion node-key="hierarchy"
+            :default-expanded-keys="TreeExpandKey" :current-node-key="currentNodeKey" @node-click="ElTreeClick">
+        <template #default="{ node, data }">
+            <div class="data-custom-tree-node" :id="`${idPrefix}${data['hierarchy']}`">{{ node.label }}</div>
+        </template>
+    </ElTree>
+</template>
+
+<script setup>
+import {ref,watch,nextTick} from "vue";
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => ([])
+    },
+    autoExpandKeys: {
+        type: Array,
+        default: () => ([])
+    },
+    idPrefix: {
+        type: String,
+        default: 'tree-data-'
+    }
+})
+
+//变量
+const ElTreeProps = ref({
+    label: 'name',
+    children: 'treeList'
+})
+
+const TreeExpandKey = ref(props.autoExpandKeys)
+
+//监听
+watch(() => [
+    props.autoExpandKeys,
+], ([expandKeys]) => {
+    TreeExpandKey.value = expandKeys
+    setTreeNodeClick()
+})
+
+nextTick(() => {
+    setTreeNodeClick()
+});
+
+//设置选中
+const currentNodeKey = ref('')
+const setTreeNodeClick = () => {
+    const keys = TreeExpandKey.value
+    if (keys.length > 0) {
+        currentNodeKey.value = keys[keys.length - 1]
+    } else {
+        currentNodeKey.value = ''
+    }
+}
+
+//事件
+const emit = defineEmits(['nodeTap'])
+
+//节点被点击
+const ElTreeClick = async (data,node) => {
+    let autoKeysArr = []
+    await getNodeExpandKeys(node, autoKeysArr)
+    const autoKeys = autoKeysArr.reverse()
+    const key = getNodeKeys(autoKeys)
+    emit('nodeTap', {node, data, keys: autoKeys, key})
+}
+
+const getNodeKeys = (keys) => {
+    if (keys.length > 0) {
+        return keys[keys.length - 1]
+    } else {
+        return ''
+    }
+}
+
+//处理自动展开的节点KEY
+const getNodeExpandKeys = async (node, newKeys) => {
+    const parent = node?.parent ?? []
+    const hierarchy = node?.data?.hierarchy ?? ''
+    if (hierarchy) {
+        newKeys.push(hierarchy)
+        await getNodeExpandKeys(parent, newKeys)
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.data-custom-tree-node {
+    position: relative;
+    display: flex;
+    align-items: center;
+    width: 100%;
+    color: var(--ui-TC);
+}
+</style>

+ 158 - 0
src/views/other-file/components/WbsTree.vue

@@ -0,0 +1,158 @@
+<template>
+    <ElTree class="hc-tree-node" :props="ElTreeProps" :load="ElTreeLoadNode" lazy highlight-current accordion node-key="primaryKeyId"
+            :default-expanded-keys="defaultExpandedCids" @node-click="ElTreeClick">
+        <template #default="{ node, data }">
+            <div class="data-custom-tree-node" :id="`${idPrefix}${data['primaryKeyId']}`">
+                <div class="label" :class="node.level === 1?'level-name':''">{{ node.label }}</div>
+            </div>
+        </template>
+    </ElTree>
+</template>
+
+<script setup>
+import {ref,nextTick,watch} from "vue";
+import imageApi from '~api/other-file/imageData';
+import {isItem,getArrValue} from "vue-utils-plus"
+//参数
+const props = defineProps({
+    projectId: {
+        type: [String,Number],
+        default: ''
+    },
+    contractId: {
+        type: [String,Number],
+        default: ''
+    },
+    autoExpandKeys: {
+        type: Array,
+        default: () => ([])
+    },
+    idPrefix: {
+        type: String,
+        default: 'wbs-tree-'
+    },
+    isAutoKeys: {
+        type: Boolean,
+        default: true
+    },
+    isAutoClick: {
+        type: Boolean,
+        default: true
+    },
+})
+
+//变量
+const ElTreeProps = ref({
+    label: 'title',
+    children: 'children',
+    isLeaf: 'notExsitChild'
+})
+
+const isAutoKeys = ref(props.isAutoKeys)
+const TreeExpandKey = ref(props.autoExpandKeys)
+const projectId = ref(props.projectId);
+const contractId = ref(props.contractId);
+
+//监听
+watch(() => [
+    props.isAutoKeys,
+    props.autoExpandKeys,
+    props.projectId,
+    props.contractId,
+], ([AutoKeys, expandKeys, UserProjectId, UserContractId]) => {
+    isAutoKeys.value = AutoKeys
+    TreeExpandKey.value = expandKeys
+    projectId.value = UserProjectId
+    contractId.value = UserContractId
+})
+
+//树形结构异步加载数据
+const defaultExpandedCids = ref([])
+const ElTreeLoadNode = async (node, resolve) => {
+    let parentId = '';
+    if (node.level !== 0) {
+        const nodeData = node?.data ?? {};
+        parentId = nodeData?.id
+    }
+    //获取数据
+    const {error, code, data} = await imageApi.getWbsTreeList({
+        contractId: contractId.value || '',
+        parentId
+    })
+    //处理数据
+    if (!error && code === 200) {
+        let clickKey = '', defaultExpandedArr = [];
+        const keys = TreeExpandKey.value || []
+        const resData = getArrValue(data)
+        if (keys.length > 0) {
+            let lastKey = keys[keys.length-1];
+            for (const item of resData) {
+                //自动展开
+                if (isItem(keys,item?.primaryKeyId)) {
+                    defaultExpandedArr.push(item?.primaryKeyId)
+                }
+                //最后一个,选中点击
+                if (item?.primaryKeyId === lastKey) {
+                    clickKey = item?.primaryKeyId
+                }
+            }
+        } else if (node.level === 0) {
+            defaultExpandedArr.push(resData[0]?.primaryKeyId)
+        }
+        //自动展开
+        defaultExpandedCids.value = defaultExpandedArr
+        resolve(resData)
+        //最后一个,执行点击
+        if (props.isAutoClick && clickKey) {
+            await nextTick(() => {
+                document.getElementById(`${props.idPrefix}${clickKey}`)?.click()
+            })
+        }
+    } else {
+        resolve([])
+    }
+}
+
+//事件
+const emit = defineEmits(['nodeTap'])
+
+//节点被点击
+const ElTreeClick = async (data,node) => {
+    if (isAutoKeys.value) {
+        let autoKeysArr = []
+        await getNodeExpandKeys(node, autoKeysArr)
+        const autoKeys = autoKeysArr.reverse()
+        emit('nodeTap', {node, data, keys: autoKeys})
+    } else {
+        emit('nodeTap', {node, data, keys: []})
+    }
+}
+
+//处理自动展开的节点KEY
+const getNodeExpandKeys = async (node, newKeys) => {
+    const parent = node?.parent ?? []
+    const primaryKeyId = node?.data?.primaryKeyId ?? ''
+    if (primaryKeyId) {
+        newKeys.push(primaryKeyId)
+        await getNodeExpandKeys(parent, newKeys)
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.data-custom-tree-node {
+    position: relative;
+    display: flex;
+    align-items: center;
+    width: 100%;
+    color: var(--ui-TC);
+    .label {
+        flex: auto;
+        font-size: 16px;
+    }
+    .label.level-name {
+        font-size: 18px;
+        font-weight: bold;
+    }
+}
+</style>

+ 141 - 203
src/views/other-file/image-data.vue

@@ -1,189 +1,116 @@
 <template>
-    <n-divider dashed title-placement="left">影像资料</n-divider>
-    <div class="p-6 pt-0 hc-image-data-content-box">
-        <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
-            <template #header v-if="btn_sort">
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_sort?.textInfo">
-                    <template #trigger>
-                        <n-button type="primary" @click="showSortModalClick">分类管理</n-button>
-                    </template>
-                    <span>{{btn_sort?.textInfo}}</span>
-                </n-popover>
+    <div class="hc-layout-box">
+        <HcCard :scrollbar="false" actionSize="lg">
+            <template #header>
+                <HcTooltip keys="image-data-sort">
+                    <el-button hc-btn type="primary" @click="showSortModalClick">
+                        <HcIcon name="grid_view"/>
+                        <span>分类管理</span>
+                    </el-button>
+                </HcTooltip>
             </template>
-            <n-collapse accordion>
-                <template v-for="item in classIfyListData" :key="item.id">
-                    <n-collapse-item :name="item.id">
-                        <template #header>
-                            <div class="header-title-box">
-                                <i class="cicon-star"/>
-                                <span class="ml-2">
-                                    {{item['classfName']}}({{item['count']>0?item['count']:0}})【{{item['projectStage']}}】 - {{parseInt(item['fileType'])===1?'视频文件':'图片文件'}}
-                                </span>
-                            </div>
-                        </template>
-                        <div class="hc-collapse-list-box">
-                            <div class="item-box" @click="viewClick(item)">查看</div>
-                            <div class="item-box" @click="uploadClick(item)" v-if="btn_upload">上传图像</div>
-                        </div>
-                    </n-collapse-item>
-                </template>
-            </n-collapse>
-        </n-card>
-    </div>
-    <!--分类管理-->
-    <n-modal v-model:show="showSortModal">
-        <n-card class="w-990">
-            <div class="modal-card-box">
-                <div class="mb-4 title-box">
-                    <span class="text-2xl">分类管理</span>
-                    <i class="_icon-close" @click="showSortModal = false"/>
-                </div>
-                <div class="text-orange text-xs mb-8">隐藏分类之后,在主页面不会显示该分类入口</div>
-                <div class="data-table-box">
-                    <n-data-table :loading="tableLoading" :columns="tableColumns" :data="tableData" :pagination="false" :single-line="false" striped/>
+            <el-scrollbar>
+                <div class="hc-table-ref-box">
+                    <el-table hc :data="tableListData" :loading="tableLoading" row-key="id" stripe>
+                        <el-table-column prop="index" label="序号" width="80">
+                            <template #default="scope">
+                                {{scope.$index + 1}}
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="classfName" label="分类名称"/>
+                        <el-table-column prop="count" label="数量"/>
+                        <el-table-column prop="projectStage" label="所属阶段"/>
+                        <el-table-column prop="fileType" label="文件类型">
+                            <template #default="scope">
+                                {{scope.row.fileType == 1 ? '视频文件' : '图片文件'}}
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="操作" align="center" width="130">
+                            <template #default="scope">
+                                <HcTooltip keys="tasks_flow_edit">
+                                    <el-button type="primary" size="small" text @click="viewClick(scope.row)">查看</el-button>
+                                </HcTooltip>
+                                <HcTooltip keys="tasks_flow_edit">
+                                    <el-button type="primary" size="small" text @click="uploadClick(scope.row)">上传</el-button>
+                                </HcTooltip>
+                            </template>
+                        </el-table-column>
+                    </el-table>
                 </div>
+            </el-scrollbar>
+        </HcCard>
+        <!--分类管理 弹框-->
+        <el-dialog v-model="showSortModal" title="分类管理" width="62rem" custom-class="hc-modal-border">
+            <el-alert title="隐藏分类之后,在主页面不会显示该分类入口" type="warning" :closable="false"/>
+            <div class="modal-dialog">
+                <el-scrollbar>
+                    <div class="hc-table-ref-box">
+                        <el-table hc :data="classTableData" :loading="classTableLoading" row-key="id" stripe>
+                            <el-table-column prop="index" label="序号" width="80">
+                                <template #default="scope">
+                                    {{scope.$index + 1}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="classfName" label="分类名称"/>
+                            <el-table-column prop="projectStage" label="所属阶段"/>
+                            <el-table-column prop="fileType" label="资料类型">
+                                <template #default="scope">
+                                    {{scope.row.fileType == 1 ? '视频文件' : '图片文件'}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column label="操作" align="center" width="130">
+                                <template #default="scope">
+                                    <el-button type="info" size="small" @click="saveConfig(scope.row)" v-if="scope.row.isShow">隐藏分类</el-button>
+                                    <el-button type="primary" size="small" @click="saveConfig(scope.row)" v-else>显示分类</el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                    </div>
+                </el-scrollbar>
             </div>
-        </n-card>
-    </n-modal>
+        </el-dialog>
+    </div>
 </template>
 
 <script setup>
-import {onMounted,ref,watch} from 'vue'
-import {useRoute} from 'vue-router'
-import router from '~src/router/index';
-import {useAppStore} from "~src/store/index";
-import imageData from '~api/other-file/imageData';
-//import {smallButton, smallThinButton} from "~src/plugins/renderele";
-import {removeStore} from "~src/utils/lib/storage";
-
+import {onMounted,ref} from 'vue'
+import {useAppStore} from "~src/store";
+import {useRouter, useRoute} from 'vue-router'
+import imageApi from '~api/other-file/imageData';
+import {delStoreData} from '~src/utils/storage'
+import {getArrValue} from "vue-utils-plus"
+
+//变量
+const router = useRouter()
 const useRoutes = useRoute()
 const useAppState = useAppStore()
-
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 
-const routerQuery = useRoutes?.query;
-const MenuBarKey = routerQuery?.MenuBarKey || '';
-
-//按钮气泡开关
-const bubbleVal = ref(useAppState.getBubble);
-
-//监听
-watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getBubble,
-], ([UserProjectId,UserContractId,Bubble]) => {
-    //项目合同数据
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    //按钮气泡开关
-    bubbleVal.value = Bubble
-})
-
-//获取气泡数据
-const getButtonsVal = (value) => {
-    return useAppState.getButtonsVal(value)
-}
-
-//气泡数据
-const btn_upload = ref(getButtonsVal('image-data-upload'))
-const btn_sort = ref(getButtonsVal('image-data-sort'))
-
-removeStore({name: 'TreeExpandKeys'})
-removeStore({name: 'TreeExpandedKeys'})
-removeStore({name: 'TreeCurrentNodeKey'})
-
-const showSortModal = ref(false)
-
 //渲染完成
 onMounted(() => {
+    delStoreData('TreeExpandKeys')
+    delStoreData('TreeExpandedKeys')
+    delStoreData('TreeCurrentNodeKey')
     getClassIfyList()
 })
 
 //获取数据
-const classIfyListData = ref([]);
-const getClassIfyList = () => {
-    imageData.getClassIfyList({
-        projectId: projectId.value,
-        contractId: contractId.value
-    }).then(res => {
-        classIfyListData.value = res?.data?.data || [];
-    })
-}
-
-//展开分类管理弹窗
-const showSortModalClick = () => {
-    showSortModal.value = true
-    getClassifyShowConfigList()
-}
-
-//获取分类管理数据
-const getClassifyShowConfigList = () => {
-    imageData.getClassifyShowConfigList({
+const tableLoading = ref(false)
+const tableListData = ref([])
+const getClassIfyList = async () => {
+    tableLoading.value = true
+    const { error, code, data } = await imageApi.getClassIfyList({
         projectId: projectId.value,
         contractId: contractId.value
-    }).then(res => {
-        tableData.value = res?.data?.data || [];
     })
-}
-
-//表格数据
-const tableLoading = ref(false)
-const tableData = ref([])
-const createColumns = ({toggle}) => {
-    return [
-        {title: '序号', key: 'key', width: 80, align: 'center',
-            render(_, index) {
-                return index + 1
-            }
-        },
-        {title: '分类名称', key: 'classfName'},
-        {title: '所属阶段', key: 'projectStage', width: 100, align: 'center'},
-        {title: '资料类型', key: 'fileType', width: 100, align: 'center',
-            render(row) {
-                if (parseInt(row.fileType) === 1) {
-                    return '视频文件'
-                } else if (parseInt(row.fileType) === 2) {
-                    return '图片文件'
-                } else {
-                    return '未知'
-                }
-            }
-        },
-        {title: "操作", key: "actions", width: 120, align: 'center',
-            render(row) {
-                if (row.isShow) {
-                    //return smallThinButton("隐藏分类", row, toggle)
-                } else {
-                    //return smallButton("显示分类", row, toggle)
-                }
-            }
-        }
-    ];
-};
-const tableColumns = createColumns({
-    toggle(row) {
-        saveClassifyShowConfig(row)
+    //处理数据
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableListData.value = getArrValue(data)
+    } else {
+        tableListData.value = []
     }
-})
-
-//保存客户端分类显隐记录
-const saveClassifyShowConfig = (row) => {
-    imageData.saveClassifyShowConfig({
-        showList: [{
-            projectId: projectId.value,
-            contractId: contractId.value,
-            classifyId: row.id,
-            isShow: row.isShow?0:1,
-            id: row['showId']
-        }]
-    }).then(res => {
-        if (res?.data?.code === 200) {
-            row.isShow = !row.isShow
-            getClassIfyList()
-        }
-    })
 }
 
 //查看影像资料
@@ -191,7 +118,6 @@ const viewClick = (item) => {
     router.push({
         path: '/other-file/image-view',
         query: {
-            MenuBarKey: MenuBarKey,
             type: item['storageDirectoryFormat'],
             fileType: item['fileType'],
             id: item.id,
@@ -204,51 +130,63 @@ const uploadClick = (item) => {
     router.push({
         path: '/other-file/image-form',
         query: {
-            MenuBarKey: MenuBarKey,
             dataType: item['storageDirectoryFormat'], //存储目录格式 1按部位存储,2按日期存储
             fileType: item['fileType'], //文件类型,1视频文件,2图片文件
-            classifyId: item.id,  //classifyId,分类ID,
+            classifyId: item.id,  //classifyId, 分类ID,
         }
     })
 }
-</script>
 
-<style lang="scss" scoped>
-@import '../../styles/other-file/image-data.scss';
-</style>
+//展开分类管理弹窗
+const showSortModal = ref(false)
+const showSortModalClick = () => {
+    showSortModal.value = true
+    getClassifyShowConfigList()
+}
+//获取分类管理数据
+const classTableLoading = ref(false)
+const classTableData = ref([])
+const getClassifyShowConfigList = async () => {
+    classTableLoading.value = true
+    const { error, code, data } = await imageApi.getClassifyShowConfigList({
+        projectId: projectId.value,
+        contractId: contractId.value
+    })
+    //处理数据
+    classTableLoading.value = false
+    if (!error && code === 200) {
+        classTableData.value = getArrValue(data)
+    } else {
+        classTableData.value = []
+    }
+}
 
-<style lang="scss">
-.hc-image-data-content-box  {
-    .n-collapse .n-collapse-item {
-        user-select: none;
-        border: 1px solid #EEEEEE;
-        border-radius: 3px;
-        transition: border-color .3s var(--n-bezier);
-        .n-collapse-item__header {
-            padding: 15px;
-            border-radius: 3px;
-            transition: initial;
-            .n-collapse-item__header-main {
-                position: relative;
-                transition: color .3s;
-                .n-collapse-item-arrow {
-                    position: absolute;
-                    right: 0;
-                    transition: transform .15s var(--n-bezier), color .1s;
-                }
-            }
-            &.n-collapse-item__header--active {
-                color: var(--hc-primary);
-                background: #F9F9F9;
-                .n-collapse-item__header-main,
-                .n-collapse-item-arrow{
-                    color: inherit;
-                }
-            }
-        }
-        .n-collapse-item__content-wrapper .n-collapse-item__content-inner {
-            padding-top: 0;
-        }
+//保存客户端分类显隐记录
+const saveConfig = async (row) => {
+    const { error, code } = await imageApi.saveClassifyShowConfig({
+        showList: [{
+            projectId: projectId.value,
+            contractId: contractId.value,
+            classifyId: row.id,
+            isShow: row.isShow?0:1,
+            id: row['showId']
+        }]
+    })
+    //处理数据
+    if (!error && code === 200) {
+        row.isShow = !row.isShow
+        getClassIfyList()
     }
 }
+</script>
+
+<style lang="scss" scoped>
+.hc-layout-box {
+    position: relative;
+    height: 100%;
+}
+.modal-dialog {
+    position: relative;
+    max-height: 550px;
+}
 </style>

+ 87 - 437
src/views/other-file/image-form.vue

@@ -1,187 +1,115 @@
 <template>
-    <n-divider dashed title-placement="left">
-        <span class="text-hover" @click="goToBack()">影像资料</span>
-        <span class="ml-2">/</span>
-        <span class="ml-2">上传</span>
-    </n-divider>
     <div class="hc-layout-box">
-        <div class="hc-layout-left-box view-wbs-type" v-if="dataType === 1" :style="'width:' + leftWidth + 'px;'">
+        <div class="hc-layout-left-box" :style="'width:' + leftWidth + 'px;'"  v-if="dataType === 1">
             <div class="hc-project-box">
-                <div class="text-xl text-cut project-alias-box">
-                    <i class="hcicon-xiangmu"/>
-                    <span class="ml-2">{{projectInfo['projectAlias']}}</span>
+                <div class="hc-project-icon-box">
+                    <HcIcon name="layers"/>
+                </div>
+                <div class="ml-2 project-name-box">
+                    <span class="text-xl text-cut project-alias">{{projectInfo['projectAlias']}}</span>
+                    <div class="text-xs text-cut project-name">{{projectInfo['name']}}</div>
                 </div>
-                <div class="text-xs text-cut project-name">{{projectInfo['name']}}</div>
             </div>
-            <div class="hc-el-tree-box" v-if="dataType === 1">
-                <HcTree type="file-image-view" :params="treeParams" :props="wbsElTreeProps" lazy :autoExpandKeys="TreeAutoExpandKeys" @node-click="nodeWbsElTreeClick"/>
+            <div class="hc-tree-box">
+                <el-scrollbar>
+                    <WbsTree :autoExpandKeys="TreeAutoExpandKeys" :projectId="projectId" :contractId="contractId" @nodeTap="nodeWbsElTreeClick"/>
+                </el-scrollbar>
             </div>
             <!--左右拖动-->
             <div class="horizontal-drag-line" @mousedown="onmousedown"/>
         </div>
         <div class="hc-layout-content-box">
-            <n-card :segmented="{content: true}">
-                <template #header>
-                    <div class="hc-card-header">
-                        <div class="text-lg">上传{{fileType === 1?'视频':''}} {{fileType === 2?'图片':''}}</div>
-                    </div>
-                </template>
-                <div class="hc-card-content-box">
+            <HcCard :title="`上传${fileType === 1 ? '视频' : fileType === 2 ? '图片' : ''}`" :scrollbar="false" actionSize="lg">
+                <el-scrollbar>
                     <div class="hc-form-box w-750">
-                        <n-form ref="formRef" :model="formValue" :rules="rules" label-placement="left" label-width="auto" size="large">
-                            <n-form-item label="上传日期" path="uploadTime">
-                                <n-date-picker class="flex-1" v-model:formatted-value="formValue.uploadTime" value-format="yyyy-MM-dd" type="date"/>
-                            </n-form-item>
-                            <n-form-item label="上传文件" path="imageUrl" v-if="fileType <= 2">
-                                <div class="w-full flex-1">
-                                    <n-upload :action="action" :headers="getTokenHeader()" list-type="image-card" :with-credentials="true" :max="fileType === 2?10:1"
-                                              :multiple="fileType === 2" :accept="fileType === 1?videoAccept:fileType === 2?imageAccept:null" :file-list="uploadFileList" style="width: auto;"
-                                              @update:file-list="fileListUpdate" @finish="uploadFinish" @preview="handlePreview" @before-upload="beforeUpload" @remove="removeUpload"/>
-                                    <div class="w-full mt-3">
-                                        <div class="text-red" v-if="fileType === 1">请上传MP4、MOV格式的视频文件,文件大小不超过500M</div>
-                                        <div class="text-red" v-if="fileType === 2">请上传JPG/JPEG、PNG格式的图片文件,文件大小不超过60M</div>
-                                    </div>
+                        <el-form ref="formRef" :model="formValue" :rules="rules" label-width="auto" size="large">
+                            <el-form-item label="上传日期" prop="uploadTime">
+                                <el-date-picker v-model="formValue.uploadTime" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"/>
+                            </el-form-item>
+                            <el-form-item label="上传文件" prop="imageUrl">
+                                <div class="w-full">
+                                    <HcUploads :fileList="uploadFileList" :accept="fileType === 1 ? videoAccept : fileType === 2 ? imageAccept : null"
+                                               :limit="fileType === 2 ? 10 : 1" :size="fileType === 2 ? 30 : 500" :viewer="false" @change="uploadsChange"
+                                               @del="uploadsDel" @preview="uploadsPreview"/>
                                 </div>
-                                <n-modal v-model:show="previewImageModal" preset="card" class="w-606">
-                                    <img :src="previewImageUrl" alt="" style="width: 100%" v-if="fileType === 2">
-                                    <video class="preview-video" :src="previewImageUrl" controls="controls" autoplay="autoplay" v-if="fileType === 1">
-                                        您的浏览器不支持 video
-                                    </video>
-                                </n-modal>
-                            </n-form-item>
-                            <n-form-item label="题名" path="title">
-                                <n-input class="flex-1" v-model:value="formValue.title" placeholder="请输入题名"/>
-                            </n-form-item>
-                            <div class="flex">
-                                <n-form-item class="flex-1" :class="fileType === 2?'mr-4':''" label="拍摄者" path="shootingUser">
-                                    <n-input v-model:value="formValue.shootingUser" placeholder="请输入拍摄者"/>
-                                </n-form-item>
-                                <n-form-item class="flex-1 ml-4" label="照片号" path="photoCode" v-if="formValue.type == 2">
-                                    <n-input v-model:value="formValue.photoCode" placeholder="请输入照片号"/>
-                                </n-form-item>
-                            </div>
-                            <n-form-item label="拍摄时间" path="shootingTimeStr">
-                                <n-date-picker class="flex-1" v-model:formatted-value="formValue.shootingTimeStr" value-format="yyyy-MM-dd" type="date"/>
-                            </n-form-item>
-                            <div class="flex" v-if="fileType === 2">
-                                <n-form-item class="flex-1 mr-4" label="底片号">
-                                    <n-input v-model:value="formValue.filmCode" placeholder="请输入底片号"/>
-                                </n-form-item>
-                                <n-form-item class="flex-1 ml-4" label="参见号">
-                                    <n-input v-model:value="formValue.seeAlsoCode" placeholder="请输入参见号"/>
-                                </n-form-item>
-                            </div>
-                            <n-form-item label="文字说明">
-                                <n-input v-model:value="formValue.textContent" placeholder="请输入文字说明" type="textarea" :autosize="{minRows: 3,maxRows: 5}"/>
-                            </n-form-item>
-                        </n-form>
+                            </el-form-item>
+                            <el-form-item label="题名" prop="title">
+                                <el-input v-model="formValue.title" placeholder="请输入题名"/>
+                            </el-form-item>
+                        </el-form>
                     </div>
-                    <div class="card-right-table-box" v-if="dataType !== 1">
-                        <n-data-table :columns="tableColumns" :data="tableData" :pagination="false" :single-line="false" striped/>
-                    </div>
-                </div>
+                </el-scrollbar>
                 <template #action>
-                    <div class="text-center w-750">
-                        <n-button type="primary" strong secondary class="px-4 mr-6" @click="toBackClick">返回上一级</n-button>
-                        <n-button type="primary" strong secondary class="px-4 mr-6" :loading="saveLoading" v-if="dataType !== 1" @click="saveLogClick">保存并再次添加下一条记录</n-button>
-                        <n-button type="primary" class="px-4" :loading="saveLoading" @click="saveClick">保存</n-button>
-                    </div>
+                    <HcTooltip keys="image-data-add">
+                        <el-button type="primary" hc-btn>
+                            <HcIcon name="save"/>
+                            <span>保存</span>
+                        </el-button>
+                    </HcTooltip>
+                    <HcTooltip keys="image-data-download">
+                        <el-button hc-btn>
+                            <HcIcon name="undo"/>
+                            <span>返回</span>
+                        </el-button>
+                    </HcTooltip>
                 </template>
-            </n-card>
+            </HcCard>
         </div>
     </div>
 </template>
 
 <script setup>
-import {nextTick,onMounted, ref,watch} from 'vue'
-import {useRoute} from 'vue-router'
-import router from '~src/router/index';
-import {useAppStore} from "~src/store/index";
-import imageData from '~api/other-file/imageData';
-import HcTree from "~com/plugins/element/HcTree.vue"
-import {getTokenHeader} from '~src/api/request/header';
-import {setStore,getStore} from "~src/utils/lib/storage";
-import oss from "~api/oss";
-import moment from 'moment';
-
+import {onMounted, ref, watch} from 'vue'
+import {useAppStore} from "~src/store";
+import {useRouter, useRoute} from 'vue-router'
+import WbsTree from "./components/WbsTree.vue"
+import imageApi from '~api/other-file/imageData';
+import {getStoreData, setStoreData} from '~src/utils/storage'
+import {getArrValue,getObjNullValue} from "vue-utils-plus"
+
+//变量
+const router = useRouter()
 const useRoutes = useRoute()
 const useAppState = useAppStore()
-
-const routerQuery = useRoutes?.query;
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 const projectInfo = ref(useAppState.getProjectInfo);
+const isCollapse = ref(useAppState.getCollapse)
 
-const TreeAutoExpandKeys = ref(getStore({name: 'TreeExpandKeys'}) || [])
-
+//路由参数
+const routerQuery = useRoutes?.query;
 //存储目录格式 1按部位存储,2按日期存储
-const dataType = parseInt(routerQuery?.dataType) || 1;
-const classifyId = routerQuery?.classifyId || '';
-const fileType = parseInt(routerQuery?.fileType) || 2; //文件类型,1视频文件,2图片文件
-const wbsNodeIdsStr = routerQuery?.wbsId || '';
 const dataId = routerQuery?.id || '';
-const MenuBarKey = routerQuery?.MenuBarKey || '';
-
-//上传组件参数
-const action = '/api/blade-resource/oss/endpoint/upload-file';
-const imageAccept = 'image/png,image/jpg,image/jpeg';
-const videoAccept = 'video/*';
-
-//处理日期格式
-const setDateFormat = (val) => {
-    return (val + '').length === 1 ? `0${val}` : val;
-}
-//今天的日期,年月日
-const year = moment().get('year');
-const month = setDateFormat(moment().get('month') + 1);
-const date = setDateFormat(moment().get('date'));
-const toDayDate = `${year}-${month}-${date}`;
+const dataType = parseInt(routerQuery?.type + '') || 1;
+const fileType = parseInt(routerQuery?.fileType + '') || 2;
 
 //监听
 watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getProjectInfo,
-], ([UserProjectId, UserContractId,UserProjectInfo]) => {
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    projectInfo.value = UserProjectInfo
+    useAppState.getCollapse
+], ([Collapse]) => {
+    isCollapse.value = Collapse
 })
 
-nextTick(() => {
-
-})
+//自动展开缓存
+const TreeAutoExpandKeys = ref(getStoreData('TreeExpandKeys') || [])
 
+//渲染完成
 onMounted(() => {
-    //获取数据详情
-    if (dataId) queryById()
-})
 
-const nodeItemInfo = ref({})
-const nodeDataInfo = ref({})
+})
 
-//树形结构数据
-const wbsElTreeProps = {label: 'title', children: 'children', isLeaf: 'exsitChild'}
-const treeParams = ref({contractId: contractId.value})
+//项目树被点击
+const nodeWbsElTreeClick = () => {
 
-//树被点击
-const nodeWbsElTreeClick = ({data,node}) => {
-    nodeItemInfo.value = node
-    nodeDataInfo.value = data
-    if (data.leaf === true) {
-        formValue.value.wbsId = data['primaryKeyId']
-    }
 }
 
 //表单相关数据
-const uploadInfoListData = ref([])
-const saveLoading = ref(false)
 const formRef = ref(null)
 const formValue = ref({})
 const rules = {
     uploadTime: {
         required: true,
-        trigger: ["blur", "change"],
+        trigger: "blur",
         message: "请选择上传日期"
     },
     imageUrl: {
@@ -190,12 +118,12 @@ const rules = {
     },
     title: {
         required: true,
-        trigger: ["blur", "input"],
+        trigger: "blur",
         message: "请输入题名"
     },
     shootingUser: {
         required: true,
-        trigger: ["blur", "input"],
+        trigger: "blur",
         message: "请输入拍摄者"
     },
     photoCode: {
@@ -206,269 +134,43 @@ const rules = {
             }
             return true;
         },
-        trigger: ["blur", "change"]
+        trigger: "blur"
     },
     shootingTimeStr: {
         required: true,
-        trigger: ["blur", "change"],
+        trigger: "blur",
         message: "请选择拍摄时间"
     },
 }
 
+//上传组件参数
+const action = '/api/blade-resource/oss/endpoint/upload-file';
+const imageAccept = 'image/png,image/jpg,image/jpeg';
+const videoAccept = 'video/*';
 //上传文件的相关数据
 const previewFileList = ref([])
 const uploadFileList = ref([])
-
-//表单默认数据
-const formDataFormat = (info) => {
-    //表单数据
-    formValue.value = {
-        ...info,
-        type: fileType + '' || '2',
-        wbsId: info?.wbsId || wbsNodeIdsStr,
-        classifyId: info?.classifyId || classifyId,
-        projectId: info?.projectId || projectId.value,
-        contractId: info?.contractId || contractId.value,
-    }
-    //原始文件地址
-    let imageUrl = info?.imageUrl || '';
-    let imageUrlArr = imageUrl?imageUrl.split(','):[]
-    //PDF地址
-    let pdfUrl = info?.pdfUrl || '';
-    let pdfUrlArr = pdfUrl?pdfUrl.split(','):[]
-    //处理数据
-    if (imageUrlArr.length > 0) {
-        //状态处理
-        let InfoPdfUrl = false
-        if (pdfUrlArr.length === imageUrlArr.length) {
-            InfoPdfUrl = true
-        } else {
-            InfoPdfUrl = false
-        }
-        //遍历数据
-        for (let i = 0; i < imageUrlArr.length; i++) {
-            let item = imageUrlArr[i];
-            uploadFileList.value.push({
-                url: item,
-                status: "finished",
-                thumbnailUrl: item
-            })
-            previewFileList.value.push(item)
-            //添加到上传的数组里
-            uploadInfoListData.value.push({
-                pdfUrl: InfoPdfUrl?pdfUrlArr[i]:'',
-                page: '',
-                link: item
-            })
-        }
-    } else {
-        uploadFileList.value = []
-        previewFileList.value = []
-        uploadInfoListData.value = []
-    }
+//上传的文件结果
+const uploadsChange = ({ type, fileList}) => {
+    console.log(type, fileList)
 }
-
-formDataFormat({})
-
-//详情
-const queryById = () => {
-    imageData.queryById({id: dataId}).then(({data}) => {
-        if (data.code === 200) {
-            let info = data?.data || {};
-            formDataFormat(info)
-        } else {
-            window.$message?.error(data.msg || '请求异常')
-        }
-    })
+//预览上传的文件
+const uploadsPreview = ({ index, fileArr, fileList}) => {
+    console.log(index, fileArr, fileList)
 }
 
-//上传前
-const beforeUpload = async ({file}) => {
-    let maxTrillion = 0;
-    let fileSizeData = file?.file?.size
-    if (fileType === 2) {
-        maxTrillion = 60
-    } else {
-        maxTrillion = 500
-    }
-    let maxSize = maxTrillion * 1024 * 1024
-    if (fileSizeData > maxSize) {
-        window.$message?.warning(`文件大小,不能过${maxTrillion}M!`);
-        return false;
-    } else {
-        formValue.value.fileSize = fileSizeData
-        return true;
-    }
-}
-//上传完成
-const uploadFinish = ({file,event}) => {
-    let res = JSON.parse(event?.target?.response);
-    let data = res?.data;
-    if (data?.link) {
-        file.url = data?.link;
-        file.name = data?.name;
-        file.thumbnailUrl = data?.link;
-        //添加到上传的数组里
-        uploadInfoListData.value.push({
-            pdfUrl: data?.pdfUrl,
-            page: data?.page,
-            link: data?.link
-        })
-    }
-}
-//文件列表改变
-const fileListUpdate = (fileList) => {
-    let fileArr = []
-    fileList.forEach(item => {
-        fileArr.push(item.url)
-    })
-    uploadFileList.value = fileList
-    previewFileList.value = fileArr
-}
-//预览
-const previewImageModal = ref(false);
-const previewImageUrl = ref("");
-const handlePreview = (file) => {
-    previewImageUrl.value = file?.url;
-    previewImageModal.value = true;
-}
-//删除文件
-const removeUpload = ({file}) => {
-    if (file.name) {
-        oss.removeFile({
-            fileName: file.name
-        }).then(({data}) => {
-            if (data.code === 200) {
-                formValue.value.imageUrl = ''
-                return true
-            } else {
-                window.$message?.error(data.msg || '删除异常')
-                return false
-            }
-        }).catch(() => {
-            return false
-        })
-    } else {
-        uploadFileList.value = []
-        return true
-    }
-}
-
-//上传记录表格
-const tableColumns = [
-    {title: '序号', key: 'index', width: 80, align: 'center',
-        render(_, index) {
-            return index + 1
-        }
-    },
-    {title: '上传日期', key: 'uploadTime'},
-    {title: '题名', key: 'title'},
-    {title: '拍摄者', key: 'shootingUser'},
-    {title: '拍摄时间', key: 'shootingTimeStr'}
-];
-const tableData = ref([])
-
-//验证表单数据
-const shootingTimeStr = ref('')
-const verifyFormData = (log = false) => {
-    //处理文件数据
-    const fileList = uploadInfoListData.value || []
-    //遍历数据
-    let imageUrl = '', pdfUrl = '';
-    for (let i = 0; i < fileList.length; i++) {
-        let item = fileList[i];
-        if (imageUrl) {
-            imageUrl += ',' + item?.link
-        } else {
-            imageUrl = item?.link
-        }
-        if (pdfUrl) {
-            pdfUrl += ',' + item?.pdfUrl
-        } else {
-            pdfUrl = item?.pdfUrl
-        }
-    }
-    //设置数据
-    const formData = formValue.value;
-    formData.imageUrl = imageUrl
-    formData.pdfUrl = pdfUrl
-    shootingTimeStr.value = formData['shootingTimeStr'] || ''
-    //验证表单数据
-    if (!formData.wbsId && dataType === 1) {
-        window.$message?.warning('请先选择节点')
-    } else {
-        formRef.value?.validate((errors) => {
-            if (!errors) {
-                let id = formData?.id || ''
-                if (id) {
-                    updateImageclassifyFile(log)
-                } else {
-                    addImageclassifyFile(log)
-                }
-            }
-        })
-    }
-}
-
-//保存
-const saveClick = () => {
-    verifyFormData(false)
-}
-
-//保存并再次添加下一条记录
-const saveLogClick = () => {
-    verifyFormData(true)
-}
-
-//新增影音资料信息
-const addImageclassifyFile = (log = false) => {
-    saveLoading.value = true;
-    imageData.addImageclassifyFile(formValue.value).then(({data}) => {
-        saveLoading.value = false;
-        if (data.code === 200) {
-            window.$message?.success('保存成功')
-            if (log) {
-                tableData.value.push(JSON.parse(JSON.stringify(formValue.value)))
-                formDataFormat({})
-            } else {
-                toBackClick()
-            }
-        } else {
-            window.$message?.error(data.msg || '保存异常')
-        }
-    }).catch(() => {
-        saveLoading.value = false;
-    })
-}
-
-//修改影音资料信息
-const updateImageclassifyFile = (log = false) => {
-    saveLoading.value = true;
-    imageData.updateImageclassifyFile(formValue.value).then(({data}) => {
-        saveLoading.value = false;
-        if (data.code === 200) {
-            window.$message?.success('保存成功')
-            if (log) {
-                tableData.value.push(JSON.parse(JSON.stringify(formValue.value)))
-                formDataFormat({})
-            } else {
-                toBackClick()
-            }
-        } else {
-            window.$message?.error(data.msg || '保存异常')
-        }
-    }).catch(() => {
-        saveLoading.value = false;
-    })
+//删除上传的文件
+const uploadsDel = ({ row, fileList}) => {
+    console.log(row, fileList)
 }
 
-
 //左右拖动,改变树形结构宽度
 const leftWidth = ref(382);
 const onmousedown = () => {
+    const leftNum = isCollapse.value ? 142 : 272
     document.onmousemove = (ve) => {
-        let diffVal = ve.clientX + 2;
-        if (diffVal >= 310 && diffVal <= 900) {
+        let diffVal = ve.clientX - leftNum;
+        if(diffVal >= 310 && diffVal <= 900) {
             leftWidth.value = diffVal;
         }
     }
@@ -477,62 +179,10 @@ const onmousedown = () => {
         document.onmouseup = null;
     }
 }
-
-//处理自动展开的节点KEY
-const getNodeExpandKeys = async (node, newKeys) => {
-    if (node?.data?.primaryKeyId) {
-        newKeys.push(node.data.primaryKeyId)
-        await getNodeExpandKeys(node.parent,newKeys)
-    }
-}
-
-const NodeExpandKeys = async () => {
-    let newKeysArr = [], node = nodeItemInfo.value || {}
-    await getNodeExpandKeys(node,newKeysArr)
-    const treeKeys = newKeysArr.reverse()
-    await setStore({name: 'TreeExpandKeys', content: treeKeys})
-}
-
-//处理data类型的自动展开
-const dataNodeExpandKeys = async () => {
-    let TimeStr = shootingTimeStr.value || ''
-    let TimeArr = TimeStr.split('-')
-    if (TimeStr && TimeArr.length > 0) {
-        let timeKey = TimeArr[0] + '-' + TimeArr[1];
-        await setStore({name: 'TreeExpandedKeys', content: [timeKey]})
-        await setStore({name: 'TreeCurrentNodeKey', content: timeKey})
-    }
-}
-
-//返回上页
-const toBackClick = async () => {
-    if (dataType === 1) {
-        await NodeExpandKeys()
-    } else if (dataType === 2) {
-        await dataNodeExpandKeys()
-    }
-    router.push({
-        path: '/other-file/image-view',
-        query: {
-            MenuBarKey: MenuBarKey,
-            fileType: fileType,
-            type: dataType,
-            id: classifyId,
-        }
-    })
-}
-
-//回到影像资料页
-const goToBack = async () => {
-    router.push({
-        path: '/other-file/image-data',
-        query: {MenuBarKey: MenuBarKey}
-    })
-}
 </script>
 
 <style lang="scss" scoped>
-@import '../../styles/other-file/image-data.scss';
+@import '../../styles/other-file/image-form.scss';
 </style>
 
 <style lang="scss">

+ 267 - 301
src/views/other-file/image-view.vue

@@ -1,293 +1,290 @@
 <template>
-    <n-divider dashed title-placement="left">
-        <span class="text-hover" @click="goToBack()">影像资料</span>
-        <span class="ml-2">/</span>
-        <span class="ml-2">查看</span>
-    </n-divider>
     <div class="hc-layout-box">
-        <div class="hc-layout-left-box" :class="dataType === 1?'view-wbs-type':'view-date-type'" :style="'width:' + leftWidth + 'px;'">
-            <div class="hc-project-box" v-if="dataType === 1">
-                <div class="text-xl text-cut project-alias-box">
-                    <i class="hcicon-xiangmu"/>
-                    <span class="ml-2">{{projectInfo['projectAlias']}}</span>
+        <div class="hc-layout-left-box" :style="'width:' + leftWidth + 'px;'">
+            <template v-if="dataType === 1">
+                <div class="hc-project-box">
+                    <div class="hc-project-icon-box">
+                        <HcIcon name="layers"/>
+                    </div>
+                    <div class="ml-2 project-name-box">
+                        <span class="text-xl text-cut project-alias">{{projectInfo['projectAlias']}}</span>
+                        <div class="text-xs text-cut project-name">{{projectInfo['name']}}</div>
+                    </div>
                 </div>
-                <div class="text-xs text-cut project-name">{{projectInfo['name']}}</div>
-            </div>
-            <div class="hc-el-tree-box" v-if="dataType === 1">
-                <HcTree type="file-image-view" :params="treeParams" :props="wbsElTreeProps" lazy :autoExpandKeys="TreeAutoExpandKeys" @node-click="nodeWbsElTreeClick"/>
-            </div>
-            <div class="hc-el-tree-box" v-else>
-                <HcTree type="file-image-view" :props="dateElTreeProps" node-key="hierarchy" :data="dateElTreeData" :default-expanded-keys="TreeExpandedKeys" :current-node-key="TreeCurrentNodeKey" @node-click="dateWbsElTreeClick"/>
+                <div class="hc-tree-box">
+                    <el-scrollbar>
+                        <WbsTree :autoExpandKeys="TreeAutoExpandKeys" :projectId="projectId" :contractId="contractId" @nodeTap="nodeWbsElTreeClick"/>
+                    </el-scrollbar>
+                </div>
+            </template>
+            <div class="hc-tree-box date-tree" v-else>
+                <el-scrollbar>
+                    <HcTreeData :datas="dateElTreeData" :autoExpandKeys="TreeExpandedKeys" @nodeTap="dateWbsElTreeClick"/>
+                </el-scrollbar>
             </div>
             <!--左右拖动-->
             <div class="horizontal-drag-line" @mousedown="onmousedown"/>
         </div>
         <div class="hc-layout-content-box">
-            <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
+            <HcCard :scrollbar="false" actionSize="lg">
                 <template #header>
-                    <div class="hc-card-header flex items-center">
-                        <div class="text-lg mr-3">图文组合列表</div>
-                        <div class="w-60 ml-3">
-                            <n-input v-model:value="searchForm.queryStr" type="text" placeholder="根据题名名称或拍摄者搜索" @keyup="keyUpEvent" clearable/>
-                        </div>
-                        <div class="ml-3">
-                            <n-button type="primary" class="w-20" @click="searchClick">搜索</n-button>
-                        </div>
-                    </div>
+                    <HcTooltip keys="image-data-add">
+                        <el-button type="primary" hc-btn :disabled="!queryKey" @click="addFormFile">
+                            <HcIcon name="add_box"/>
+                            <span>新增文件</span>
+                        </el-button>
+                    </HcTooltip>
+                    <HcTooltip keys="image-data-download">
+                        <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="downloadClick">
+                            <HcIcon name="download"/>
+                            <span>下载</span>
+                        </el-button>
+                    </HcTooltip>
+                    <HcTooltip keys="image-data-del">
+                        <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="delClick">
+                            <HcIcon name="delete"/>
+                            <span>删除</span>
+                        </el-button>
+                    </HcTooltip>
                 </template>
-                <template #header-extra>
-                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_add?.textInfo" v-if="btn_add">
-                        <template #trigger>
-                            <n-button strong secondary type="primary" @click="addFormFile">
-                                <span class="mr-2">新增文件</span>
-                                <i class="_icon-add"/>
-                            </n-button>
-                        </template>
-                        <span>{{btn_add?.textInfo}}</span>
-                    </n-popover>
+                <template #extra>
+                    <div class="w-60">
+                        <el-input v-model="searchForm.queryStr" size="large" placeholder="根据题名名称或拍摄者搜索" clearable @keyup="keyUpEvent"/>
+                    </div>
+                    <div class="ml-2">
+                        <el-button type="primary" size="large" @click="searchClick">搜索</el-button>
+                    </div>
                 </template>
-                <div class="hc-img-list-box">
-                    <div class="img-list-item" v-for="item in pageListData" :key="item.id">
-                        <div class="img-box" v-if="item.type !== 1">
-                            <HcImage class="el-image-box" ui="el-image-box a" :src="setImageUrl(item.imageUrl)"/>
-                        </div>
-                        <div class="img-box" v-else>
-                            <video :src="item.imageUrl">
-                                您的浏览器不支持 video
-                            </video>
+                <el-scrollbar>
+                    <div class="hc-table-ref-box">
+                        <el-table ref="tableListRef" hc :data="tableListData" :loading="tableLoading" stripe @selection-change="tableSelectionChange">
+                            <el-table-column type="selection" width="50" />
+                            <el-table-column prop="num" label="序号" width="80">
+                                <template #default="scope">
+                                    {{scope.$index + 1}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="info" label="文件详情">
+                                <template #default="scope">
+                                    <div class="hc-table-col-item">
+                                        <div class="img-box" v-if="scope.row.type !== 1">
+                                            <HcImg class="hc-image" :src="setImageUrl(scope.row.imageUrl)"/>
+                                        </div>
+                                        <div class="img-box" v-else>
+                                            <video :src="scope.row.imageUrl">
+                                                您的浏览器不支持 video
+                                            </video>
+                                        </div>
+                                        <div class="content-box">
+                                            <div class="text-cut title">{{scope.row.title}}</div>
+                                            <div class="shootingUser">拍摄者:{{scope.row.shootingUser}}</div>
+                                            <div class="shootingTimeStr">拍摄时间:{{scope.row.shootingTimeStr}}</div>
+                                            <div class="fileSize">文件大小:{{scope.row.fileSize}}</div>
+                                        </div>
+                                    </div>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="textContent" label="文字说明"/>
+                            <el-table-column label="操作" align="center" width="130">
+                                <template #default="scope">
+                                    <HcTooltip keys="image-data-preview">
+                                        <el-button type="primary" size="small" text @click="previewClick(scope.row)">查看</el-button>
+                                    </HcTooltip>
+                                    <HcTooltip keys="image-data-edit">
+                                        <el-button type="primary" size="small" text @click="editClick(scope.row)">编辑</el-button>
+                                    </HcTooltip>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                    </div>
+                </el-scrollbar>
+                <template #action>
+                    <div class="lr-dialog-footer">
+                        <div class="left">
+                            <el-button size="large" @click="goToBack">返回上级</el-button>
                         </div>
-                        <div class="content-box">
-                            <div class="title-box">
-                                <div class="font-bold text-xl text-cut text-title">{{item.title}}</div>
-                                <div class="icon-box">
-                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_preview?.textInfo" v-if="btn_preview">
-                                        <template #trigger>
-                                            <div class="icon-item" @click="previewClick(item)">
-                                                <i class="HIcon-yulan"/>
-                                            </div>
-                                        </template>
-                                        <span>{{btn_preview?.textInfo}}</span>
-                                    </n-popover>
-                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_edit?.textInfo" v-if="btn_edit">
-                                        <template #trigger>
-                                            <div class="icon-item" @click="editClick(item)">
-                                                <i class="HIcon-bianji"/>
-                                            </div>
-                                        </template>
-                                        <span>{{btn_edit?.textInfo}}</span>
-                                    </n-popover>
-                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_download?.textInfo" v-if="btn_download">
-                                        <template #trigger>
-                                            <div class="icon-item" @click="downloadClick(item)">
-                                                <i class="HIcon-xiazaiwenjian"/>
-                                            </div>
-                                        </template>
-                                        <span>{{btn_download?.textInfo}}</span>
-                                    </n-popover>
-                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_del?.textInfo" v-if="btn_del">
-                                        <template #trigger>
-                                            <div class="icon-item">
-                                                <n-popconfirm @positive-click="delClick(item)">
-                                                    <template #icon>
-                                                        <i class="hcicon-bangzhu text-red"/>
-                                                    </template>
-                                                    <template #trigger>
-                                                        <i class="HIcon-shanchu"/>
-                                                    </template>
-                                                    <span>请谨慎考虑此操作,确认要删除吗?</span>
-                                                </n-popconfirm>
-                                            </div>
-                                        </template>
-                                        <span>{{btn_del?.textInfo}}</span>
-                                    </n-popover>
-                                </div>
-                            </div>
-                            <div class="text-content text-gray">
-                                <div class="text-linecut-3">{{item.textContent}}</div>
-                            </div>
-                            <div class="foot-text-box">
-                                <span>拍摄者:{{item.shootingUser}}</span>
-                                <span class="ml-10">拍摄时间:{{item.shootingTimeStr}}</span>
-                                <span class="ml-10">文件大小:{{item.fileSize}}</span>
-                            </div>
+                        <div class="right">
+                            <HcPages :pages="searchForm" @change="pageChange"/>
                         </div>
                     </div>
-                </div>
-                <template #action>
-                    <HcPage :pages="searchForm" @change="pageChange"/>
                 </template>
-            </n-card>
+            </HcCard>
         </div>
+        <!--视频预览 弹框-->
+        <el-dialog v-model="previewVideoModal" title="预览" width="47rem" destroy-on-close custom-class="hc-modal-border">
+            <video class="preview-video" :src="previewVideoUrl" controls="controls" autoplay="autoplay" v-if="previewVideoUrl">
+                您的浏览器不支持 video
+            </video>
+        </el-dialog>
     </div>
-    <n-modal v-model:show="previewVideoModal" preset="card" class="w-750">
-        <video class="preview-video" :src="previewVideoUrl" controls="controls" autoplay="autoplay" v-if="previewVideoUrl">
-            您的浏览器不支持 video
-        </video>
-    </n-modal>
 </template>
 
 <script setup>
-import {onMounted,ref,watch} from 'vue'
-import {useRoute} from 'vue-router'
-import router from '~src/router/index';
-import {useAppStore} from "~src/store/index";
-import imageData from '~api/other-file/imageData';
-import HcTree from "~com/plugins/element/HcTree.vue"
-import HcImage from "~com/plugins/element/HcImage.vue"
-import HcPage from "~com/plugins/naive/HcPage.vue"
-import {setStore,getStore} from "~src/utils/lib/storage";
-import {isObjNull} from "~src/utils/lib/isApp";
-import {download} from '~src/utils/lib/tools';
-
-//初始变量
+import {onMounted, ref, watch} from 'vue'
+import {useAppStore} from "~src/store";
+import {useRouter, useRoute} from 'vue-router'
+import WbsTree from "./components/WbsTree.vue"
+import HcTreeData from "./components/HcTreeData.vue"
+import imageApi from '~api/other-file/imageData';
+import {getStoreData, setStoreData} from '~src/utils/storage'
+import {getArrValue,getObjNullValue} from "vue-utils-plus"
+
+//变量
+const router = useRouter()
 const useRoutes = useRoute()
 const useAppState = useAppStore()
-
-const routerQuery = useRoutes?.query;
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 const projectInfo = ref(useAppState.getProjectInfo);
+const isCollapse = ref(useAppState.getCollapse)
 
-const TreeAutoExpandKeys = ref(getStore({name: 'TreeExpandKeys'}) || [])
-const TreeExpandedKeys = ref(getStore({name: 'TreeExpandedKeys'}) || [])
-const TreeCurrentNodeKey = ref(getStore({name: 'TreeCurrentNodeKey'}) || '')
-
+//路由参数
+const routerQuery = useRoutes?.query;
 //存储目录格式 1按部位存储,2按日期存储
-const dataType = parseInt(routerQuery?.type) || 1;
 const dataId = routerQuery?.id || '';
-const MenuBarKey = routerQuery?.MenuBarKey || '';
-const fileType = parseInt(routerQuery?.fileType) || 2;
-
-//按钮气泡开关
-const bubbleVal = ref(useAppState.getBubble);
+const dataType = parseInt(routerQuery?.type + '') || 1;
+const fileType = parseInt(routerQuery?.fileType + '') || 2;
 
 //监听
 watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getProjectInfo,
-    useAppState.getBubble
-], ([UserProjectId,UserContractId,UserProjectInfo,Bubble]) => {
-    //项目合同数据
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    projectInfo.value = UserProjectInfo
-    //按钮气泡开关
-    bubbleVal.value = Bubble
+    useAppState.getCollapse
+], ([Collapse]) => {
+    isCollapse.value = Collapse
 })
 
-//获取气泡数据
-const getButtonsVal = (value) => {
-    return useAppState.getButtonsVal(value)
-}
-
-//气泡数据
-const btn_add = ref(getButtonsVal('image-data-add'))
-const btn_preview = ref(getButtonsVal('image-data-preview'))
-const btn_edit = ref(getButtonsVal('image-data-edit'))
-const btn_download = ref(getButtonsVal('image-data-download'))
-const btn_del = ref(getButtonsVal('image-data-del'))
+//自动展开缓存
+const TreeAutoExpandKeys = ref(getStoreData('TreeExpandKeys') || [])
+const TreeExpandedKeys = ref(getStoreData('TreeExpandedKeys') || [])
+const TreeCurrentNodeKey = ref(getStoreData('TreeCurrentNodeKey') || '')
 
 //渲染完成
 onMounted(() => {
+    const nodeKey = TreeCurrentNodeKey.value
     if (dataType === 2 && dataId) {
         getYearDateTree()
-        //TreeExpandedKeys.value = ['2022-06']
-        //TreeCurrentNodeKey.value = '2022-06'
-    }
-})
-
-//搜索和分页数据
-const searchForm = ref({wbsIdsStr: null, contractId: contractId.value, projectId:projectId.value, queryStr: null, classifyId: dataId, current: 1, size: 20, total: 0})
-
-const nodeItemInfo = ref({})
-const nodeDataInfo = ref({})
-
-//树形结构数据
-const wbsElTreeProps = {label: 'title', children: 'children', isLeaf: 'exsitChild'}
-const treeParams = ref({contractId: contractId.value})
-
-//树被点击
-const wbsNodeIdsStr = ref('')
-const nodeWbsElTreeClick = ({data,node}) => {
-    nodeItemInfo.value = node
-    nodeDataInfo.value = data
-    if (data.leaf === true) {
-        searchForm.value.wbsIdsStr = data?.primaryKeyId || ''
-        wbsNodeIdsStr.value = data?.primaryKeyId || ''
+        queryKey.value = nodeKey
+        searchForm.value.queryDate = nodeKey
         searchForm.value.current = 1;
         getTableData()
     } else {
-        pageListData.value = []
-        searchForm.value.total = 0
+        queryKey.value = ''
     }
-}
+})
 
-//日期树
-const dateElTreeProps = {label: 'name', children: 'treeList'}
+//获取时间结构
 const dateElTreeData = ref([])
-//树被点击
-const dateWbsElTreeClick = ({data,node}) => {
-    nodeItemInfo.value = node
+const getYearDateTree = async () => {
+    const { error, code, data } = await imageApi.getYearDateTree({
+        projectId: projectId.value,
+        contractId: contractId.value,
+        classifyId: dataId
+    })
+    //处理数据
+    if (!error && code === 200) {
+        dateElTreeData.value = getArrValue(data)
+    } else {
+        dateElTreeData.value = []
+    }
+}
+//日期树被点击
+const nodeDataInfo = ref({})
+const dateWbsElTreeClick = ({data, keys, key}) => {
+    queryKey.value = key
     nodeDataInfo.value = data
+    //缓存自动展开
+    TreeExpandedKeys.value = keys
+    TreeCurrentNodeKey.value = key
+    setStoreData('TreeExpandedKeys', keys)
+    setStoreData('TreeCurrentNodeKey', key)
+    //改变搜索表单数据
     searchForm.value.queryDate = data['hierarchy'] || ''
+    searchForm.value.wbsIdsStr = null
     searchForm.value.current = 1;
     getTableData()
 }
 
-const NodeExpandKeys = async () => {
-    let newKeysArr = [], node = nodeItemInfo.value || {}
-    await getNodeExpandKeys(node,newKeysArr)
-    const treeKeys = newKeysArr.reverse()
-    await setStore({name: 'TreeExpandKeys', content: treeKeys})
-}
-
-//处理自动展开的节点KEY
-const getNodeExpandKeys = async (node, newKeys) => {
-    if (node?.data?.primaryKeyId) {
-        newKeys.push(node.data.primaryKeyId)
-        await getNodeExpandKeys(node.parent,newKeys)
+//项目树被点击
+const nodeWbsElTreeClick = ({data, keys}) => {
+    if (data.leaf === true) {
+        nodeDataInfo.value = data
+        queryKey.value = data['primaryKeyId'] || ''
+        //缓存自动展开
+        TreeAutoExpandKeys.value = keys
+        setStoreData('TreeExpandKeys', keys)
+        //改变搜索表单数据
+        searchForm.value.queryDate = null
+        searchForm.value.wbsIdsStr = data?.primaryKeyId || ''
+        searchForm.value.current = 1;
+        getTableData()
+    } else {
+        queryKey.value = ''
+        nodeDataInfo.value = {}
+        searchForm.value.queryDate = null
+        searchForm.value.wbsIdsStr = null
+        tableListData.value = []
+        searchForm.value.total = 0
     }
 }
 
-//获取时间结构
-const getYearDateTree = () => {
-    imageData.getYearDateTree({
-        projectId: projectId.value,
-        contractId: contractId.value,
-        classifyId: dataId
-    }).then(res => {
-        dateElTreeData.value = res?.data?.data || [];
-    })
-}
+//搜索和分页数据
+const queryKey = ref(null)
+const searchForm = ref({
+    queryStr: null, classifyId: dataId, wbsIdsStr: null,
+    current: 1, size: 20, total: 0
+})
 
 //回车搜索
 const keyUpEvent = (e) => {
     if (e.key === "Enter") {
-        searchForm.value.current = 1;
-        getTableData()
+        searchClick()
     }
 }
 
 //搜索
 const searchClick = () => {
-    searchForm.value.current = 1;
-    getTableData()
+    if (queryKey.value) {
+        searchForm.value.current = 1;
+        getTableData()
+    } else {
+        window?.$message?.warning('请先在左边选择一个树节点')
+    }
 }
+
 //分页被点击
-const pageChange = (res) => {
-    searchForm.value.current = res.current;
-    searchForm.value.size = res.size;
+const pageChange = ({current, size}) => {
+    searchForm.value.current = current
+    searchForm.value.size = size
     getTableData()
 }
 
 //获取数据
-const pageListData = ref([]);
+const tableListRef = ref(null)
+const tableLoading = ref(false)
+const tableListData = ref([])
 const getTableData = async () => {
-    const {data} = await imageData.getPageList(searchForm.value)
-    let res = data['data'] || {}
-    searchForm.value.total = res.total || 0
-    pageListData.value = res['records'] || []
+    tableLoading.value = true
+    const {error, code, data} = await imageApi.getPageList({
+        ...searchForm.value,
+        projectId: projectId.value,
+        contractId: contractId.value
+    })
+    //判断状态
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableListData.value = getArrValue(data['records'])
+        searchForm.value.total = data['total'] || 0
+    } else {
+        tableListData.value = []
+        searchForm.value.total = 0
+    }
+}
+
+//多选
+const tableCheckedKeys = ref([]);
+const tableSelectionChange = (rows) => {
+    tableCheckedKeys.value = rows.filter((item) => {
+        return (item??'') !== '';
+    })
 }
 
 //处理图片预览问题
@@ -305,18 +302,18 @@ const setImageUrl = (url) => {
 }
 
 //预览
-const previewVideoModal = ref(false)
 const previewVideoUrl = ref('')
+const previewVideoModal = ref(false)
 const previewClick = async ({id,type,imageUrl}) => {
-    let url = imageUrl || '';
-    if (url) {
+    if (imageUrl) {
         if (parseInt(type) === 1) {
-            previewVideoUrl.value = url
+            previewVideoUrl.value = imageUrl
             previewVideoModal.value = true
         } else {
-            const {data} = await imageData.imageClassificationFile({ids: id})
-            const imgUrl = isObjNull(data?.data)
-            if (!imgUrl && data.code === 200) {
+            const {error, code, data} = await imageApi.imageClassificationFile({ids: id}, false)
+            //判断状态
+            const imgUrl = getObjNullValue(data)
+            if (!error && code === 200 && imgUrl) {
                 window.open(data?.data,"_blank");
             } else {
                 window.$message?.warning('预览资料文件异常');
@@ -327,23 +324,36 @@ const previewClick = async ({id,type,imageUrl}) => {
     }
 }
 
-//删除文件
-const delClick = (item) => {
-    imageData.removeImageclassifyFile({
-        ids: item.id
-    }).then(({data}) => {
-        if (data.code === 200) {
-            window.$message?.success('删除成功')
-            getTableData()
-        } else {
-            window.$message?.error(data.msg || '删除异常')
+//新增文件
+const addFormFile = () => {
+    router.push({
+        path: '/other-file/image-form',
+        query: {
+            wbsId: queryKey.value,  //树节点ID
+            dataType: dataType,     //存储目录格式 1按部位存储,2按日期存储
+            fileType: fileType,     //文件类型,1视频文件,2图片文件
+            classifyId: dataId,     //classifyId,分类ID,
+        }
+    })
+}
+
+//编辑修改
+const editClick = ({id}) => {
+    router.push({
+        path: '/other-file/image-form',
+        query: {
+            wbsId: queryKey.value,  //树节点ID
+            dataType: dataType,     //存储目录格式 1按部位存储,2按日期存储
+            fileType: fileType,     //文件类型,1视频文件,2图片文件
+            classifyId: dataId,     //classifyId,分类ID,
+            id: id  //数据ID
         }
     })
 }
 
 //下载文件
-const downloadClick = ({id,imageUrl}) => {
-    let url = imageUrl || '';
+const downloadClick = () => {
+    /*let url = imageUrl || '';
     if (url) {
         let urlArr = url.split(',')
         if (urlArr.length === 1) {
@@ -355,80 +365,36 @@ const downloadClick = ({id,imageUrl}) => {
         }
     } else {
         window.$message?.warning('暂无可下载的资料文件');
-    }
-}
-
-//处理data类型的自动展开
-const dataNodeExpandKeys = () => {
-    let node = nodeItemInfo.value || {}
-    let id = node?.data?.hierarchy || ''
-    if (id) {
-        setStore({name: 'TreeExpandedKeys', content: [id]})
-        setStore({name: 'TreeCurrentNodeKey', content: id})
-    }
+    }*/
 }
 
-//编辑修改
-const editClick = async ({id}) => {
-    if (dataType === 1) {
-        await NodeExpandKeys()
-    } else if (dataType === 2) {
-        dataNodeExpandKeys()
-    }
-    router.push({
-        path: '/other-file/image-form',
-        query: {
-            MenuBarKey: MenuBarKey,
-            wbsId: wbsNodeIdsStr.value, //树节点ID
-            dataType: dataType, //存储目录格式 1按部位存储,2按日期存储
-            classifyId: dataId,  //classifyId,分类ID,
-            fileType: fileType,
-            id: id  //数据ID
+//删除文件
+const delClick = () => {
+    /*imageData.removeImageclassifyFile({
+        ids: item.id
+    }).then(({data}) => {
+        if (data.code === 200) {
+            window.$message?.success('删除成功')
+            getTableData()
+        } else {
+            window.$message?.error(data.msg || '删除异常')
         }
-    })
+    })*/
 }
 
-//新增文件
-const addFormFile = async () => {
-    let state = false;
-    if (dataType === 1 && wbsNodeIdsStr.value) {
-        await NodeExpandKeys()
-        state = true
-    } else if (dataType === 2) {
-        dataNodeExpandKeys()
-        state = true
-    } else {
-        state = false
-        window?.$message?.warning('请先在左边选择一个树节点')
-    }
-    if (state) {
-        router.push({
-            path: '/other-file/image-form',
-            query: {
-                MenuBarKey: MenuBarKey,
-                wbsId: wbsNodeIdsStr.value, //树节点ID
-                dataType: dataType, //存储目录格式 1按部位存储,2按日期存储
-                fileType: fileType,
-                classifyId: dataId, //classifyId,分类ID,
-            }
-        })
-    }
-}
 
 //回到影像资料页
 const goToBack = () => {
-    router.push({
-        path: '/other-file/image-data',
-        query: {MenuBarKey: MenuBarKey}
-    })
+    router.push({path: '/other-file/image-data'})
 }
 
 //左右拖动,改变树形结构宽度
 const leftWidth = ref(382);
 const onmousedown = () => {
+    const leftNum = isCollapse.value ? 142 : 272
     document.onmousemove = (ve) => {
-        let diffVal = ve.clientX + 2;
-        if (diffVal >= 310 && diffVal <= 900) {
+        let diffVal = ve.clientX - leftNum;
+        if(diffVal >= 310 && diffVal <= 900) {
             leftWidth.value = diffVal;
         }
     }
@@ -440,7 +406,7 @@ const onmousedown = () => {
 </script>
 
 <style lang="scss" scoped>
-@import '../../styles/other-file/image-data.scss';
+@import '../../styles/other-file/image-view.scss';
 </style>
 
 <style lang="scss">

+ 136 - 234
src/views/tasks/flow.vue

@@ -1,298 +1,200 @@
 <template>
-    <n-divider dashed title-placement="left">任务流程设置</n-divider>
     <div class="hc-layout-box">
-        <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
+        <HcCard :scrollbar="false" actionSize="lg">
             <template #header>
-                <div class="hc-card-header flex items-center">
-                    <div class="flex-auto text-orange text-sm">提示:同一合同段内,只需要设置重复岗位的流程即可,其他任务岗位,系统将自动推送,无需创建更多任务流</div>
-                </div>
+                <HcTooltip keys="tasks_flow_add">
+                    <el-button hc-btn type="primary" @click="addFlowData">
+                        <HcIcon name="add_box"/>
+                        <span>新建流程</span>
+                    </el-button>
+                </HcTooltip>
             </template>
-            <template #header-extra>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_add?.textInfo" v-if="btn_add">
-                    <template #trigger>
-                        <n-button type="primary" class="px-4" @click="addFlowData">新建流程</n-button>
-                    </template>
-                    <span>{{btn_add?.textInfo}}</span>
-                </n-popover>
+            <template #extra>
+                <el-alert title="同一合同段内,只需要设置重复岗位的流程即可,其他任务岗位,系统将自动推送,无需创建更多任务流" type="error" :closable="false"/>
             </template>
-            <n-data-table :columns="columns" :data="tableData" :row-key="row => row.name" :pagination="false" :single-line="false" striped/>
+            <el-scrollbar>
+                <div class="hc-table-ref-box">
+                    <el-table hc :data="tableListData" :loading="tableLoading" row-key="id" stripe>
+                        <el-table-column prop="index" label="序号" width="80">
+                            <template #default="scope">
+                                {{scope.$index + 1}}
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="fixedFlowName" label="流程名称"/>
+                        <el-table-column prop="linkUserJoinString" label="流程详情"/>
+                        <el-table-column label="操作" align="center" width="100">
+                            <template #default="scope">
+                                <HcTooltip keys="tasks_flow_edit">
+                                    <el-button type="primary" size="small" text @click="handleTableEdit(scope.row)">编辑</el-button>
+                                </HcTooltip>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                </div>
+            </el-scrollbar>
             <template #action>
-                <HcPage :pages="searchForm" @change="pageChange"/>
+                <HcPages :pages="searchForm" @change="pageChange"/>
             </template>
-        </n-card>
-        <n-modal v-model:show="showEditModal">
-            <n-card class="w-750" :title="`${flowObj.id?'编辑':'新增'}流程`" :segmented="{content: true}">
-                <template #header-extra>
-                    <span class="text-lg text-hover" @click="showEditModal = false">
-                        <i class="_icon-close"/>
-                    </span>
-                </template>
-                <div class="hc-tasks-flow-modal-box">
-                    <div class="form-item-box">
-                        <div class="form-item-title">流程名称</div>
-                        <div class="form-item-input">
-                            <n-input type="text" v-model:value="flowObj.fixedFlowName" placeholder="请输入流程名称" />
-                        </div>
-                    </div>
-                    <div class="form-item-box">
-                        <div class="form-item-title">任务人</div>
-                        <div class="form-item-input">
-                            <TasksUser :users="flowObj.linkUserJoinString" @change="TasksUserChange"/>
-                        </div>
-                    </div>
+        </HcCard>
+        <!--新增/编辑流程 弹框-->
+        <el-dialog v-model="showEditModal" :title="`${flowFormData.id?'编辑':'新增'}流程`" width="47rem" custom-class="hc-modal-border">
+            <el-form ref="formFlowRef" :model="flowFormData" :rules="formFlowRules" label-width="auto" size="large">
+                <el-form-item label="流程名称" prop="fixedFlowName">
+                    <el-input v-model="flowFormData.fixedFlowName" placeholder="请输入流程名称"/>
+                </el-form-item>
+                <el-form-item label="任务人" prop="linkUserJoinString">
+                    <HcTasksUser ui="w-full" :users="flowFormData.linkUserJoinString" @change="tasksUserChange"/>
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="showEditModal = false">取消</el-button>
+                    <el-button type="primary" hc-btn :loading="sevaLoading" @click="saveFormClick">保存</el-button>
                 </div>
-                <template #action>
-                    <div class="text-center">
-                        <n-button class="w-20 ml-4" @click="showEditModal = false">取消</n-button>
-                        <n-button type="primary" class="w-20 ml-4" :loading="sevaLoading" @click="sevaFlowClick">保存</n-button>
-                    </div>
-                </template>
-            </n-card>
-        </n-modal>
+            </template>
+        </el-dialog>
     </div>
 </template>
 
 <script setup>
-import {ref,watch,onMounted} from "vue";
-import {useAppStore} from "~src/store/index";
-import HcPage from "~com/plugins/naive/HcPage.vue"
-import TasksUser from "~com/tasksUser/index.vue"
-//import {smallButton, smallPopover} from "~src/plugins/renderele";
+import {ref,onMounted} from "vue";
+import {useAppStore} from "~src/store";
+import {getArrValue, getObjValue} from "vue-utils-plus"
 import tasksFlowApi from '~api/tasks/flow';
 
-//初始变量
+//变量
 const useAppState = useAppStore()
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 
-//按钮气泡开关
-const bubbleVal = ref(useAppState.getBubble);
-
-//监听
-watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getBubble,
-], ([UserProjectId, UserContractId, Bubble]) => {
-    //项目合同数据
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    //按钮气泡开关
-    bubbleVal.value = Bubble
-})
-
-//获取气泡数据
-const getButtonsVal = (value) => {
-    return useAppState.getButtonsVal(value)
-}
-
-//气泡数据
-const btn_edit = ref(getButtonsVal('tasks_flow_edit'))
-const btn_add = ref(getButtonsVal('tasks_flow_add'))
-
-//搜索分页
-const searchForm = ref({current: 1, size: 20, total: 0})
-
 //渲染完成
 onMounted(() => {
     getTableData()
 })
 
-//表格表头
-const createColumns = ({edit}) => {
-    return [
-        {title: '序号', key: 'num', width: 80, align: 'center',
-            render(_, index) {
-                return index + 1
-            }
-        },
-        {title: '流程名称', key: 'fixedFlowName'},
-        {title: '流程详情', key: 'linkUserJoinString'},
-        {title: "操作", key: "actions", width: 100, align: 'center',
-            render(row) {
-                let disabled = !bubbleVal.value || !btn_edit.value?.textInfo;
-                if (btn_edit.value) {
-                    //return smallPopover(disabled,btn_edit.value?.textInfo, smallButton("编辑", row, edit))
-                } else {
-                    //return smallButton("编辑", row, edit);
-                }
-            }
-        }
-    ];
-};
-const columns = createColumns({
-    edit(row) {
-        queryFixedFlowDetail(row.id)
-    }
-})
-
-//表格数据
-const tableData = ref([]);
+//搜索表单
+const searchForm = ref({current: 1, size: 20, total: 0})
 
 //分页被点击
-const pageChange = (res) => {
-    searchForm.value.current = res.current;
-    searchForm.value.size = res.size;
+const pageChange = ({current, size}) => {
+    searchForm.value.current = current
+    searchForm.value.size = size
     getTableData()
 }
 
-//获取分页数据
-const getTableData = () => {
-    tasksFlowApi.getPageData({
+//获取数据
+const tableLoading = ref(false)
+const tableListData = ref([])
+const getTableData = async () => {
+    tableLoading.value = true
+    const { error, code, data } = await tasksFlowApi.getPageData({
         projectId: projectId.value,
         contractId: contractId.value,
         ...searchForm.value
-    }).then(({data}) => {
-        if (data.code === 200) {
-            let res = data['data'] || {}
-            tableData.value = res['records'] || []
-            searchForm.value.total = res['total'] || 0
-        } else {
-            tableData.value = []
-            searchForm.value.total = 0
-        }
-    }).catch(erro => {
-        tableData.value = []
-        searchForm.value.total = 0
-    })
-}
-
-//详情
-const queryFixedFlowDetail = (rowId) => {
-    showEditModal.value = true
-    tasksFlowApi.queryFixedFlowDetail({
-        id: rowId
-    }).then(({data}) => {
-        if (data.code === 200) {
-            let res = data['data'] || {}
-            //处理数据格式
-            let users = '', LinkList = res['fixedFlowLinkList'] || []
-            if (LinkList.length > 0) {
-                LinkList.forEach(item => {
-                    if (users) {
-                        users += `,${item['fixedFlowLinkUserName']}-${item['fixedFlowLinkUser']}`
-                    } else {
-                        users = `${item['fixedFlowLinkUserName']}-${item['fixedFlowLinkUser']}`
-                    }
-                })
-            }
-            flowObj.value = {id: res.id, fixedFlowName: res.fixedFlowName, linkUserJoinString: users}
-        } else {
-            flowObj.value = {id: '', fixedFlowName: '', linkUserJoinString: ''}
-            window?.$message?.warning(data.msg || '数据异常')
-        }
     })
+    //处理数据
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableListData.value = getArrValue(data['records'])
+        searchForm.value.total = data.total || 0
+    } else {
+        tableListData.value = []
+        searchForm.value.total = 0
+    }
 }
 
 //新增编辑数据
 const showEditModal = ref(false)
-const sevaLoading = ref(false)
-const flowObj = ref({id: '', fixedFlowName: '', linkUserJoinString: ''})
+const formFlowRef = ref(null)
+const flowFormData = ref({id: '', fixedFlowName: '', linkUserJoinString: ''})
+const formFlowRules = {
+    fixedFlowName: {
+        required: true,
+        trigger: "blur",
+        message: "请输入流程名称"
+    },
+    linkUserJoinString: {
+        required: true,
+        trigger: "blur",
+        message: "请选择任务人"
+    }
+}
 
-//新建
-const addFlowData = () => {
-    flowObj.value = {id: '', fixedFlowName: '', linkUserJoinString: ''}
-    showEditModal.value = true
+//任务人选择改变
+const tasksUserChange = (users) => {
+    flowFormData.value.linkUserJoinString = users
 }
 
-//任务人选择确认事件
-const TasksUserChange = (users) => {
-    flowObj.value.linkUserJoinString = users
+//新建流程
+const addFlowData = () => {
+    flowFormData.value = {id: '', fixedFlowName: '', linkUserJoinString: ''}
+    showEditModal.value = true
 }
 
-//保存
-const sevaFlowClick = () => {
-    const form = flowObj.value
-    if (!form.fixedFlowName) {
-        window?.$message?.warning('请先填写流程名称')
-    } else if (!form.linkUserJoinString) {
-        window?.$message?.warning('请先选择任务人')
-    } else {
-        if (!form.id) {
-            addFixedFlowData(form)
-        } else {
-            updateFixedFlowData(form)
+//编辑流程
+const handleTableEdit = async (row) => {
+    flowFormData.value = {id: '', fixedFlowName: '', linkUserJoinString: ''}
+    showEditModal.value = true
+    const { error, code, data } = await tasksFlowApi.queryFixedFlowDetail({
+        id: row?.id
+    })
+    if (!error && code === 200) {
+        let users = '',  res = getObjValue(data)
+        const list = getArrValue(res['fixedFlowLinkList'])
+        for (let i = 0; i < list.length; i++) {
+            const item = getObjValue(list[i])
+            if (users) {
+                users += `,${item['fixedFlowLinkUserName']}-${item['fixedFlowLinkUser']}`
+            } else {
+                users = `${item['fixedFlowLinkUserName']}-${item['fixedFlowLinkUser']}`
+            }
         }
+        flowFormData.value = {id: res.id, fixedFlowName: res.fixedFlowName, linkUserJoinString: users}
+    } else {
+        flowFormData.value = {id: '', fixedFlowName: '', linkUserJoinString: ''}
     }
 }
 
-//新增流程
-const addFixedFlowData = (form) => {
-    sevaLoading.value = true
-    tasksFlowApi.addFixedFlowData({
-        projectId: projectId.value,
-        contractId: contractId.value,
-        ...form
-    }).then(({data}) => {
+//提交保存
+const sevaLoading = ref(false)
+const saveFormClick = async () => {
+    const form = flowFormData.value
+    if (!form.id) {
+        sevaLoading.value = true
+        const { error, code } = await tasksFlowApi.addFixedFlowData({
+            ...form,
+            projectId: projectId.value,
+            contractId: contractId.value
+        })
+        //处理数据
         sevaLoading.value = false
-        if (data.code === 200) {
+        if (!error && code === 200) {
             showEditModal.value = false
             window?.$message?.success('保存成功')
             getTableData()
-        } else {
-            window?.$message?.warning(data.msg || '保存异常')
         }
-    }).catch(erro => {
-        sevaLoading.value = false
-    })
-}
-
-//修改流程
-const updateFixedFlowData = (form) => {
-    sevaLoading.value = true
-    tasksFlowApi.updateFixedFlowData({
-        projectId: projectId.value,
-        contractId: contractId.value,
-        ...form
-    }).then(({data}) => {
+    } else {
+        sevaLoading.value = true
+        const { error, code } = await tasksFlowApi.updateFixedFlowData({
+            ...form,
+            projectId: projectId.value,
+            contractId: contractId.value
+        })
+        //处理数据
         sevaLoading.value = false
-        if (data.code === 200) {
+        if (!error && code === 200) {
             showEditModal.value = false
             window?.$message?.success('保存成功')
             getTableData()
-        } else {
-            window?.$message?.warning(data.msg || '保存异常')
         }
-    }).catch(erro => {
-        sevaLoading.value = false
-    })
+    }
 }
-
 </script>
 
 <style lang="scss" scoped>
 .hc-layout-box {
     position: relative;
-    height: calc(100% - 60px);
-    padding: 0 24px 24px;
-    .hc-card-header {
-        position: relative;
-        font-size: initial;
-        font-weight: initial;
-    }
-}
-.hc-tasks-flow-modal-box {
-    position: relative;
-    .form-item-box {
-        position: relative;
-        display: flex;
-        .form-item-title {
-            position: relative;
-            width: 60px;
-            height: 34px;
-            display: flex;
-            align-items: center;
-            justify-content: flex-end;
-        }
-        .form-item-input {
-            flex: 1;
-            position: relative;
-            margin-left: 12px;
-        }
-    }
-    .form-item-box + .form-item-box {
-        margin-top: 20px;
-    }
+    height: 100%;
 }
 </style>
 

+ 296 - 647
src/views/tasks/hc-data.vue

@@ -1,760 +1,409 @@
 <template>
-    <n-divider dashed title-placement="left">任务查看</n-divider>
     <div class="hc-layout-box">
-        <n-card class="hc-card-overflow-box" :segmented="{content: true}">
-            <template #header>
-                <div class="hc-card-header flex items-center">
-                    <div class="hc-btn-tab-box">
-                        <n-button class="ml-3" :type="activeKey === 'key1'?'primary':''" :color="activeKey === 'key1'?'':'#999999'" ghost @click="activeClick('key1')">
-                            <i class="hcicon-yes-tasks"/>
-                            <span class="ml-1">待办任务列表</span>
-                        </n-button>
-                        <n-button class="ml-3" :type="activeKey === 'key2'?'primary':''" :color="activeKey === 'key2'?'':'#999999'" ghost @click="activeClick('key2')">
-                            <i class="hcicon-yes-tasks"/>
-                            <span class="ml-1">已办任务列表</span>
-                        </n-button>
-                        <n-button class="ml-3" :type="activeKey === 'key3'?'primary':''" :color="activeKey === 'key3'?'':'#999999'" ghost @click="activeClick('key3')">
-                            <i class="cicon-my-o"/>
-                            <span class="ml-1">我发起的任务列表</span>
-                        </n-button>
+        <!--https://codepen.io/weilanwl/pen/JjLVyOd-->
+        <HcSbTable :datas="sbTableData" :cur="sbTableKey" @tabClick="sbTableClick"/>
+        <div class="hc-content-box">
+            <HcCard :scrollbar="false" actionSize="lg">
+                <template #header>
+                    <div class="w-32">
+                        <el-select v-model="searchForm.taskType" block clearable size="large" placeholder="任务类型">
+                            <el-option v-for="item in tasksType" :label="item.dictValue" :value="item.dictKey"/>
+                        </el-select>
                     </div>
-                </div>
-            </template>
-            <template #header-extra>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_set_sign_rules?.textInfo" v-if="btn_set_sign_rules">
-                    <template #trigger>
-                        <n-button class="px-5" type="primary" strong secondary @click="showSetSignRulesModal = true">
-                            <i class="cicon-settings"/>
-                            <span class="ml-1">设置重签规则</span>
-                        </n-button>
-                    </template>
-                    <span>{{btn_set_sign_rules?.textInfo}}</span>
-                </n-popover>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_batch_review?.textInfo" v-if="btn_batch_review && activeKey === 'key1'">
-                    <template #trigger>
-                        <n-button type="primary" strong secondary class="px-5 ml-5" @click="batchCompleteApprovalTaskClick">批量审批</n-button>
-                    </template>
-                    <span>{{btn_batch_review?.textInfo}}</span>
-                </n-popover>
-            </template>
-            <div class="bg-card-main hc-sticky-box p-6 flex items-center">
-                <div class="w-32">
-                    <n-select v-model:value="searchForm.taskType" :options="tasksType" placeholder="任务类型" clearable label-field="dictValue" value-field="dictKey"/>
-                </div>
-                <div class="w-32 ml-3">
-                    <n-select v-model:value="searchForm.taskStatus" :options="tasksStatus" placeholder="任务状态" clearable label-field="dictValue" value-field="dictKey"/>
-                </div>
-                <div class="ml-3">
-                    <el-select v-model="searchForm.contractId" placeholder="合同段" clearable @change="ContractIdChange">
-                        <el-option v-for="item in projectInfo['contractInfoList'] || []" :key="item.id" :label="item.name" :value="item.id"/>
-                    </el-select>
-                </div>
-                <div class="w-32 ml-3">
-                    <n-select v-model:value="searchForm.batch" :options="reportBatch" placeholder="上报批次" clearable label-field="batch" value-field="batch"/>
-                </div>
-                <div class="w-96 ml-3">
-                    <n-date-picker v-model:formatted-value="datePickerValue" value-format="yyyy-MM-dd" type="daterange" clearable @update:formatted-value="updateFormattedValue"/>
-                </div>
-                <div class="w-60 ml-3">
-                    <n-input v-model:value="searchForm.queryValue" type="text" placeholder="请输入关键词" clearable />
-                </div>
-                <n-button type="primary" class="px-5 ml-3" @click="searchClick">搜索</n-button>
-            </div>
-            <div class="p-6 pt-0">
-                <n-data-table :columns="tableColumns" :data="tableData" :row-key="row => row.id" :pagination="false" :single-line="false" striped @update:checked-row-keys="tableHandleCheck"/>
-            </div>
-            <template #action>
-                <div class="flex items-center">
-                    <div class="flex-1">
-                        <span>审批人员中:未签字(黑色)</span>,
-                        <span class="text-green">已签字(绿色)</span>,
-                        <span class="text-orange">已废除(黄色)</span>,
-                        <span class="text-red">签字异常(红色)</span>
+                    <div class="w-32 ml-3">
+                        <el-select v-model="searchForm.taskStatus" block clearable size="large" placeholder="任务状态">
+                            <el-option v-for="item in tasksStatus" :label="item.dictValue" :value="item.dictKey"/>
+                        </el-select>
                     </div>
-                    <HcPage :pages="searchForm" @change="pageChange"/>
-                </div>
-            </template>
-        </n-card>
-    </div>
-
-    <!--任务审核-->
-    <n-modal v-model:show="showTaskReviewModal">
-        <n-card class="task-review-modal-card" :segmented="{content: true}">
-            <template #header>
-                <div class="hc-card-header flex items-center">
-                    <div class="font-bold mr-5">任务审核 【已开启电签】</div>
-                    <div class="font-bold text-main" v-if="taskReviewType==='1'">任务名称:{{taskReviewInfo.taskName}}</div>
-                </div>
-            </template>
-            <div class="hc-card-body-flex">
-                <div class="flex-iframe">
-                    <iframe width='100%' height='100%' frameborder='1' :src="batchPdfUrl"/>
-                </div>
-                <div class="flex-table" :class="activeKey === 'key1'?'':'vh'">
-                    <div class="data-table" v-if="taskReviewType==='1'">
-                        <n-data-table :columns="taskReviewColumns" :data="taskReviewData" :row-key="row => row.fileName" :bordered="false" :single-line="false" :row-props="rowProps"/>
+                    <div class="w-32 ml-3">
+                        <el-select v-model="searchForm.contractId" placeholder="合同段" block clearable size="large" @change="ContractIdChange">
+                            <el-option v-for="item in contractList" :label="item.name" :value="item.id"/>
+                        </el-select>
+                    </div>
+                    <div class="w-32 ml-3">
+                        <el-select v-model="searchForm.batch" block clearable size="large" placeholder="上报批次">
+                            <el-option v-for="item in reportBatch" :label="item.batch" :value="item.batch"/>
+                        </el-select>
+                    </div>
+                    <div class="w-64 ml-3">
+                        <HcDatePicker :dates="betweenTime" size="large" clearable @change="betweenTimeUpdate"/>
+                    </div>
+                    <div class="w-56 ml-3">
+                        <el-input v-model="searchForm.queryValue" block size="large" placeholder="请输入名称关键词检索" clearable @keyup="keyUpEvent"/>
+                    </div>
+                    <div class="ml-2">
+                        <el-button type="primary" size="large" @click="searchClick">搜索</el-button>
                     </div>
-                    <div class="data-table" v-if="taskReviewType==='2'">
-                        <n-data-table :columns="checkedRowsColumns" :data="checkedRowsRef" :row-key="row => row.parallelProcessInstanceId" :bordered="false" :single-line="false" :row-props="rowProps"/>
+                </template>
+                <template #extra>
+                    <HcTooltip keys="tasks_data_set_sign_rules">
+                        <el-button hc-btn @click="setSignRulesClick">
+                            <HcIcon name="device_hub"/>
+                            <span>设置重签规则</span>
+                        </el-button>
+                    </HcTooltip>
+                    <HcTooltip keys="tasks_data_batch_review" v-if="sbTableKey === 'key1'">
+                        <el-button hc-btn type="primary" :disabled="tableCheckedKeys.length <= 0" @click="batchApprovalTaskClick">
+                            <HcIcon name="device_hub"/>
+                            <span>批量审批</span>
+                        </el-button>
+                    </HcTooltip>
+                </template>
+                <el-scrollbar>
+                    <div class="hc-table-ref-box">
+                        <el-table ref="tableListRef" hc :data="tableListData" :loading="tableLoading" row-key="id" stripe @selection-change="tableSelectionChange">
+                            <el-table-column type="selection" width="50" />
+                            <el-table-column prop="num" label="序号" width="80">
+                                <template #default="scope">
+                                    {{scope.$index + 1}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="taskName" label="任务名称">
+                                <template #default="scope">
+                                    <span class="text-link" @click="rowTaskName(scope.row)">{{scope.row?.taskName}}</span>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="typeValue" label="任务类型" width="120"/>
+                            <el-table-column prop="taskStatus" label="任务状态" width="160">
+                                <template #default="scope">
+                                    {{ setStatusTag(scope.row?.taskStatus) }}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="startTime" label="开始时间" width="180"/>
+                            <el-table-column prop="endTime" label="限定时间" width="180"/>
+                            <el-table-column prop="taskContent" label="任务描述"/>
+                            <el-table-column prop="reportUserName" label="上报人" width="120"/>
+                            <el-table-column prop="waitingUserList" label="签字人员">
+                                <template #default="scope">
+                                    {{ setUserTag(scope.row?.waitingUserList) }}
+                                </template>
+                            </el-table-column>
+                        </el-table>
                     </div>
-                    <div class="action-foot-box" v-if="activeKey === 'key1'">
-                        <div class="radio-group-box">
-                            <span class="label">审批操作:</span>
-                            <n-radio-group v-model:value="taskReviewForm.flag" name="radiogroup">
-                                <n-space>
-                                    <n-radio value="OK">同意</n-radio>
-                                    <n-radio value="NO">废除任务</n-radio>
-                                </n-space>
-                            </n-radio-group>
+                </el-scrollbar>
+                <template #action>
+                    <div class="lr-dialog-footer">
+                        <div class="left">
+                            <span class="text-success">审批人员中:</span>
+                            <el-tag type="info" class="mx-1" effect="dark">未签字</el-tag>
+                            <el-tag type="success" class="mx-1" effect="dark">已签字</el-tag>
+                            <el-tag type="warning" class="mx-1" effect="dark">已废除</el-tag>
+                            <el-tag type="danger" class="mx-1" effect="dark">签字异常</el-tag>
                         </div>
-                        <n-divider/>
-                        <n-input v-model:value="taskReviewForm.comment" placeholder="请输入审核意见" type="textarea" :autosize="{minRows: 3,maxRows: 5}"/>
-                        <div class="action-btn-box">
-                            <n-button class="px-5" @click="showTaskReviewModal = false">取消</n-button>
-                            <n-button type="primary" class="px-5 ml-4" :loading="SMSAuthLoading" @click="ConfirmApprovalClick">确认审批</n-button>
+                        <div class="right">
+                            <HcPages :pages="searchForm" @change="pageChange"/>
                         </div>
                     </div>
-                </div>
-            </div>
-        </n-card>
-    </n-modal>
-
-    <!--设置重签规则-->
-    <n-modal v-model:show="showSetSignRulesModal">
-        <n-card class="w-606" title="设置重签规则" :segmented="{content: true}">
+                </template>
+            </HcCard>
+        </div>
+        <!--任务审核-->
+        <!--设置重签规则-->
+        <el-dialog v-model="showSetSignRulesModal" title="设置重签规则" width="38rem" custom-class="hc-modal-border">
             <div class="text-orange mb-10">
                 <span class="mr-4">提示:设置默认时长,在任务被废除需要重签的时候,规定的重签上报时间提示时间段内,系统提示用户重签信息,但是超过处理时间,系统可默认自动授权重签</span>
-                <n-checkbox v-model:checked="setPactVal">
+                <el-checkbox v-model="setPactVal" label="Option 1" size="large">
                     <span class="text-main">《授权系统自动电签协议》</span>
-                </n-checkbox>
+                </el-checkbox>
             </div>
             <div class="obj-item-cell">
                 <div class="label">默认处理时间(时)</div>
-                <HcCounter v-model:value="formReport.date"></HcCounter>
+                <HcCounter v-model:value="formReport.date" @update:modelValue="dateUpdateValue"/>
             </div>
             <div class="obj-item-cell">
                 <div class="label">开启系统自动电签</div>
-                <n-switch v-model:value="formReport.active" />
+                <el-switch v-model="formReport.active" />
             </div>
-            <template #action>
-                <div class="text-center">
-                    <n-button class="px-5" @click="showSetSignRulesModal = false">取消</n-button>
-                    <n-button type="primary" class="px-5 ml-4">保存</n-button>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="showSetSignRulesModal = false">取消</el-button>
+                    <el-button type="primary" hc-btn>保存</el-button>
                 </div>
             </template>
-        </n-card>
-    </n-modal>
-
-    <!--短信认证-->
-    <SMSAuth :show="SMSAuthShow" :loading="SMSAuthLoading" @cancel="SMSAuthCancel" @confirm="SMSAuthConfirm"/>
-
+        </el-dialog>
+    </div>
 </template>
 
 <script setup>
-import {h, ref, watch, onMounted} from "vue";
-import {useRoute} from "vue-router";
-import {useAppStore} from "~src/store/index";
-import router from '~src/router/index';
-import HcPage from "~com/plugins/naive/HcPage.vue"
-import HcCounter from "~com/counter/index.vue"
-import SMSAuth from "~com/modal/SMSAuth.vue"
-import tasksDataApi from '~api/tasks/data';
-import {isString} from "~src/utils/lib/isApp";
-import moment from 'moment';
-
-//处理路由参数
+import {h, ref, onMounted} from "vue";
+import {useAppStore} from "~src/store";
+import tasksApi from '~api/tasks/data';
+import {useRouter, useRoute} from 'vue-router'
+import HcSbTable from "~com/hc-sb-table/index.vue";
+import {isType, formValidate, deepClone} from "vue-utils-plus"
+import {ElTag} from 'element-plus'
+
+//初始变量
+const router = useRouter()
 const useRoutes = useRoute()
 const useAppState = useAppStore()
-const routerQuery = useRoutes?.query
-const MenuBarKey = routerQuery?.MenuBarKey || ''
-let activeVal = routerQuery?.active || 'key1'
+const { isObjNull, getObjValue,  getArrValue } = isType()
+
+//路由参数
+const routerQuery = useRoutes?.query;
+const activeName = routerQuery?.active || 'key1'
 
+//全局变量
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 const projectInfo = ref(useAppState.getProjectInfo);
 
-//按钮气泡开关
-const bubbleVal = ref(useAppState.getBubble);
-
-//监听
-watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getProjectInfo,
-    useAppState.getBubble,
-], ([UserProjectId,UserContractId,UserProjectInfo,Bubble]) => {
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    projectInfo.value = UserProjectInfo
-    //按钮气泡开关
-    bubbleVal.value = Bubble
-})
-
-//获取气泡数据
-const getButtonsVal = (value) => {
-    return useAppState.getButtonsVal(value)
-}
-
-//气泡数据
-const btn_batch_review = ref(getButtonsVal('tasks_data_batch_review'))
-const btn_set_sign_rules = ref(getButtonsVal('tasks_data_set_sign_rules'))
-
-//菜单类别
-const activeKey = ref(activeVal)
-
-//类别被切换
-const activeClick = (val) => {
-    activeKey.value = val
-    router.push({
-        path: useRoutes.path,
-        query: {
-            MenuBarKey: MenuBarKey,
-            active: val,
-        }
-    })
-    searchForm.value.current = 1
-    getListTableData()
-    checkSmsCode()
-}
-
-const tasksType = ref([])       //任务类型
-const tasksStatus = ref([])     //任务状态
-const reportBatch = ref([])     //上报批次
-
-//搜索表单
-const datePickerValue = ref(null)
-const searchForm = ref({
-    projectId: projectId.value, contractId: null,
-    queryValue: null, taskType: null, taskStatus: null, batch: null, startTime: null, endTime: null,
-    current: 1, size: 20, total: 0
-})
-
-//日期选择处理
-const updateFormattedValue = (val) => {
-    datePickerValue.value = val
-    if (val && val.length > 0) {
-        searchForm.value.startTime = val[0]
-        searchForm.value.endTime = val[1]
-    } else {
-        searchForm.value.startTime = null
-        searchForm.value.endTime = null
-    }
-}
-
 //渲染完成
 onMounted(() => {
+    const project = getObjValue(projectInfo.value)
+    contractList.value = getArrValue(project['contractInfoList'])
     //获取下拉数据
     queryTaskType()
     queryTaskStatus()
-    queryBatchList()
-    //获取列表数据
-    getListTableData()
-    checkSmsCode()
+    searchClick()
 })
 
+//类型处理
+const sbTableKey = ref(activeName)
+const sbTableData = ref([
+    {icon: 'schedule', label: '待办任务', key: 'key1'},
+    {icon: 'check_circle', label: '已办任务', key: 'key2'},
+    {icon: 'person', label: '我发起的', key: 'key3'},
+])
+const sbTableClick = (key) => {
+    sbTableKey.value = key
+    router.push({
+        path: useRoutes.path,
+        query: {active: key}
+    })
+    searchClick()
+}
+
 //获取任务类型
-const queryTaskType = () => {
-    tasksDataApi.queryTaskTypeStatus({
+const tasksType = ref([])
+const queryTaskType = async () => {
+    const { error, code, data } = await tasksApi.queryTaskTypeStatus({
         typeOrStatus: 'task_type'
-    }).then(({data}) => {
-        if (data.code === 200) {
-            tasksType.value = data['data']
-        } else {
-            tasksType.value = []
-        }
     })
+    if (!error && code === 200) {
+        tasksType.value = getArrValue(data)
+    } else {
+        tasksType.value = []
+    }
 }
 
 //获取任务状态
-const queryTaskStatus = () => {
-    tasksDataApi.queryTaskTypeStatus({
+const tasksStatus = ref([])
+const queryTaskStatus = async () => {
+    const { error, code, data } = await tasksApi.queryTaskTypeStatus({
         typeOrStatus: 'task_status'
-    }).then(({data}) => {
-        if (data.code === 200) {
-            tasksStatus.value = data['data']
-        } else {
-            tasksStatus.value = []
-        }
     })
+    if (!error && code === 200) {
+        tasksStatus.value = getArrValue(data)
+    } else {
+        tasksStatus.value = []
+    }
 }
 
-//合同段值改变
+//合同段
+const contractList = ref([])
 const ContractIdChange = () => {
     queryBatchList()
 }
 
 //获取上报批次
-const queryBatchList = () => {
+const reportBatch = ref([])
+const queryBatchList = async () => {
     const {contractId} = searchForm.value
-    tasksDataApi.queryBatchList({
+    const { error, code, data } = await tasksApi.queryBatchList({
         projectId: projectId.value,
         contractId: contractId || ''
-    }).then(({data}) => {
-        if (data.code === 200) {
-            reportBatch.value = data['data']
-        } else {
-            reportBatch.value = []
-        }
     })
+    if (!error && code === 200) {
+        reportBatch.value = getArrValue(data)
+    } else {
+        reportBatch.value = []
+    }
 }
 
-//搜索
-const searchClick = () => {
-    searchForm.value.current = 1
-    getListTableData()
-}
 
-//分页被点击
-const pageChange = (res) => {
-    searchForm.value.current = res.current;
-    searchForm.value.size = res.size;
-    getListTableData()
+//搜索表单
+const searchForm = ref({
+    queryValue: null, taskType: null, taskStatus: null, batch: null, startTime: null, endTime: null,
+    current: 1, size: 20, total: 0
+})
+
+//日期时间被选择
+const betweenTime = ref(null)
+const betweenTimeUpdate = ({val,arr}) => {
+    betweenTime.value = arr
+    searchForm.value.startTime = val['start']
+    searchForm.value.endTime = val['end']
 }
 
-//获取列表数据
-const getListTableData = () => {
-    searchForm.value.projectId = projectId.value
-    if(activeKey.value === 'key1') {
+//回车搜索
+const keyUpEvent = (e) => {
+    if (e.key === "Enter") {
+        searchForm.value.current = 1;
         getTableData()
-    } else if(activeKey.value === 'key2') {
-        queryUserDoneTaskList()
-    } else if (activeKey.value === 'key3') {
-        queryUserStartFlow()
     }
 }
 
-//设置用户标签
-const setUserSpan = (UserList) => {
-    let domArr = [];
-    for (let i = 0; i < UserList.length; i++) {
-        let item = UserList[i];
-        if (item['waitingUserName']) {
-            domArr.push(
-                h('span', {
-                    class: `${item.status === 2?'text-green':item.status === 3?'text-orange':item.status === 999?'text-red':''}`
-                }, item['waitingUserName'])
-            )
-            if (i < (UserList.length -1)) {
-                domArr.push(h('span', {}, '、'))
-            }
-        }
-    }
-    return domArr
+//搜索
+const searchClick = () => {
+    searchForm.value.current = 1;
+    getTableData()
 }
 
-//表格表头
-const tableColumns = [
-    {type: 'selection'},
-    {title: '序号', key: 'num', width: 80, align: 'center',
-        render(_, index) {
-            return index + 1
-        }
-    },
-    {title: '任务名称', key: 'taskName',
-        render(row) {
-            return h('div', {
-                class:'text-link',
-                onClick: () => queryApprovalParameter(row)
-            }, row.taskName)
-        }
-    },
-    {title: '任务类型', key: 'typeValue', width: 120},
-    {title: '任务状态', key: 'taskStatus', width: 160,
-        render(row) {
-            const item = row['taskStatus'];
-            return h('div', {
-                class: `${item['status'] === 2?'text-green':item['status'] === 3?'text-orange':''}`
-            }, {
-                default: () => item['statusValue']
-            })
-        }
-    },
-    {title: '开始时间', key: 'startTime', width: 180},
-    {title: '限定时间', key: 'endTime', width: 180},
-    {title: '任务描述', key: 'taskContent'},
-    {title: '上报人', key: 'reportUserName', width: 120},
-    {title: '签字人员', key: 'waitingUserList',
-        render(row) {
-            if (row['waitingUserList'].length > 0) {
-                return h('div', {}, {
-                    default: () => setUserSpan(row['waitingUserList'])
-                })
-            } else {
-                return ''
-            }
-        }
-    }
-]
-//表格数据
-const tableData = ref([]);
+//分页被点击
+const pageChange = ({current, size}) => {
+    searchForm.value.current = current
+    searchForm.value.size = size
+    getTableData()
+}
 
 //获取数据
+const tableLoading = ref(false)
+const tableListData = ref([])
 const getTableData = () => {
-    tasksDataApi.queryUserToDoTaskList(searchForm.value).then(({data}) => {
-        if (data.code === 200) {
-            let res = data['data'] || {}
-            tableData.value = res['records'] || []
-            searchForm.value.total = res.total || 0
-        } else {
-            tableData.value = []
-            searchForm.value.total = 0
-        }
-    })
+    const key = sbTableKey.value
+    tableListRef.value?.clearSelection()
+    tableCheckedKeys.value = []
+    if(key === 'key1') {
+        queryUserToDoTaskList()
+    } else if(key === 'key2') {
+        queryUserDoneTaskList()
+    } else if (key === 'key3') {
+        queryUserStartFlow()
+    }
 }
 
-//审批页详情
-const taskReviewType = ref('1')
-const taskReviewInfo = ref({})
-const queryApprovalParameter = (row) => {
-    let pid = row['parallelProcessInstanceId'] || ''
-    showTaskReviewModal.value = true
-    taskReviewType.value = '1'
-    if (row.formDataId) {
-        taskReviewInfo.value = row
-        tasksDataApi.queryApprovalParameter({
-            parallelProcessInstanceId: pid,
-            formDataId: row.formDataId,
-            approvalType: row.approvalType,
-        }).then(({data}) => {
-            if (data.code === 200) {
-                const approvalFileList = data['data']['approvalFileList'] || []
-                taskReviewData.value = approvalFileList
-                if (approvalFileList.length > 0) {
-                    batchPdfUrl.value = approvalFileList[0].fileUrl
-                }
-            } else {
-                taskReviewData.value = []
-            }
-        })
+//待办任务列表
+const queryUserToDoTaskList = async () => {
+    tableLoading.value = true
+    const { error, code, data } = await tasksApi.queryUserToDoTaskList({
+        ...searchForm.value,
+        projectId: projectId.value
+    })
+    //处理数据
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableListData.value = getArrValue(data['records'])
+        searchForm.value.total = data.total || 0
     } else {
-        taskReviewInfo.value = {}
-        window?.$message?.warning('此数据异常')
+        tableListData.value = []
+        searchForm.value.total = 0
     }
 }
-
 //获取已办任务
-const queryUserDoneTaskList = () => {
-    tasksDataApi.queryUserDoneTaskList(searchForm.value).then(({data}) => {
-        if (data.code === 200) {
-            let res = data['data'] || {}
-            tableData.value = res['records'] || []
-            searchForm.value.total = res.total || 0
-        } else {
-            tableData.value = []
-            searchForm.value.total = 0
-        }
-    })
-}
-
-//获取发起
-const queryUserStartFlow = () => {
-    tasksDataApi.queryUserStartFlow(searchForm.value).then(({data}) => {
-        if (data.code === 200) {
-            let res = data['data'] || {}
-            tableData.value = res['records'] || []
-            searchForm.value.total = res.total || 0
-        } else {
-            tableData.value = []
-            searchForm.value.total = 0
-        }
+const queryUserDoneTaskList = async () => {
+    tableLoading.value = true
+    const { error, code, data } = await tasksApi.queryUserDoneTaskList({
+        ...searchForm.value,
+        projectId: projectId.value
     })
-}
-
-//表格勾选
-const checkedRowsRef = ref([])
-const tableHandleCheck = (_,rows) => {
-    checkedRowsRef.value = rows
-}
-
-//批量审批
-const batchCompleteApprovalTaskClick = () => {
-    const rows = checkedRowsRef.value
-    if (rows.length > 0) {
-        taskReviewType.value = '2'
-        showTaskReviewModal.value = true
-        queryTaskInfo(rows[0])
+    //处理数据
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableListData.value = getArrValue(data['records'])
+        searchForm.value.total = data.total || 0
     } else {
-        window?.$message?.warning('请先勾选需要审批的数据')
+        tableListData.value = []
+        searchForm.value.total = 0
     }
 }
-
-//PDF预览地址
-const batchPdfUrl = ref('')
-//任务审核
-const showTaskReviewModal = ref(false)
-const taskReviewColumns = [
-    {title: '序号', key: 'num', width: 80, align: 'center',
-        render(_, index) {
-            return index + 1
-        }
-    },
-    {title: '文件名称', key: 'fileName'}
-]
-const taskReviewData = ref([])
-
-//批量列表
-const checkedRowsColumns = [
-    {title: '序号', key: 'num', width: 80, align: 'center',
-        render(_, index) {
-            return index + 1
-        }
-    },
-    {title: '任务名称', key: 'taskName'}
-]
-
-const taskReviewForm = ref({flag: 'OK', comment: ''})
-
-//行被点击
-const rowProps = (row) => {
-    const type = taskReviewType.value
-    return {
-        onClick: () => {
-            if (type === '1') {
-                batchPdfUrl.value = row.fileUrl
-            } else {
-                queryTaskInfo(row)
-            }
-        }
-    }
-}
-
-//批量审批获取PDF地址
-const queryTaskInfo = (row) => {
-    if (row['hc_batchPdfUrl']) {
-        batchPdfUrl.value = row['hc_batchPdfUrl']
+//获取我发起的
+const queryUserStartFlow = async () => {
+    tableLoading.value = true
+    const { error, code, data } = await tasksApi.queryUserStartFlow({
+        ...searchForm.value,
+        projectId: projectId.value
+    })
+    //处理数据
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableListData.value = getArrValue(data['records'])
+        searchForm.value.total = data.total || 0
     } else {
-        tasksDataApi.queryTaskInfo({
-            formDataId: row['formDataId'] || '',
-            approvalType: row['approvalType']
-        }).then(({data}) => {
-            if (data.code === 200) {
-                const approvalFileList = data['data']['approvalFileList'] || []
-                if (approvalFileList.length > 0) {
-                    batchPdfUrl.value = approvalFileList[0].fileUrl
-                    row['hc_batchPdfUrl'] = approvalFileList[0].fileUrl
-                } else {
-                    batchPdfUrl.value = ''
-                    row['hc_batchPdfUrl'] = ''
-                    window?.$message?.warning('PDF获取异常')
-                }
-            } else {
-                window?.$message?.warning(data.msg || 'PDF异常')
-            }
-        })
+        tableListData.value = []
+        searchForm.value.total = 0
     }
 }
 
-//短信验证有效期
-const smsCodeTime = ref('')
-const checkSmsCode = () => {
-    tasksDataApi.checkSmsCode().then(({data}) => {
-        smsCodeTime.value = data.code===200?isString(data?.data)?data?.data:'':'';
-    }).catch(() => {
-        smsCodeTime.value = '';
+//多选
+const tableListRef = ref(null)
+const tableCheckedKeys = ref([]);
+const tableSelectionChange = (rows) => {
+    tableCheckedKeys.value = rows.filter((item) => {
+        return (item??'') !== '';
     })
 }
 
+//设置状态标签
+const setStatusTag = (taskStatus) => {
+    const item = getObjValue(taskStatus)
+    return h(ElTag, {
+        type: `${item['status'] === 2 ? 'success' : item['status'] === 3 ? 'warning' : 'info'}`,
+        effect: "dark",
+        class: "mx-1"
+    }, {
+        default: () => item['statusValue']
+    })
+}
 
-//验证短信有效期
-const isCheckSmsCodeTime = () => {
-    const smsTime = smsCodeTime.value;
-    if (!smsTime) {
-        return true
+//设置用户标签
+const setUserTag = (UserList) => {
+    const list = getArrValue(UserList)
+    if (list.length > 0) {
+        return h('div', {}, {
+            default: () => setUserTags(list)
+        })
     } else {
-        const toDayTime = moment().format("YYYY-MM-DD HH:mm:ss");
-        return moment(smsTime).isBefore(toDayTime)
+        return ''
     }
 }
-
-
-//确认审批
-const SMSAuthShow = ref(false)
-const SMSAuthLoading = ref(false)
-const ConfirmApprovalClick = () => {
-    const formData = taskReviewForm.value
-    if (formData.flag === 'NO' && !formData.comment) {
-        window?.$message?.warning('请先输入审核意见')
-    } else {
-        const ShowAuth = isCheckSmsCodeTime()
-        SMSAuthShow.value = ShowAuth
-        //免短信验证
-        if (!ShowAuth) {
-            const type = taskReviewType.value
-            if (type === '1') {
-                saveCompleteApprovalTask()
-            } else {
-                batchCompleteApprovalTask()
-            }
-            checkSmsCode()
+const setUserTags = (list) => {
+    let tagArr = [];
+    for (let i = 0; i < list.length; i++) {
+        let item = getObjValue(list[i]);
+        if (item['waitingUserName']) {
+            tagArr.push(
+                h(ElTag, {
+                    type: `${item.status === 2 ? 'success' : item.status === 3 ? 'warning' : item.status === 999 ? 'danger' : 'info'}`,
+                    effect: "dark",
+                    class: "mx-1"
+                }, {
+                    default: () => item['waitingUserName']
+                })
+            )
         }
     }
+    return tagArr
 }
 
-//短信验证取消
-const SMSAuthCancel = () => {
-    SMSAuthShow.value = false
-}
-
-//短信验证确认
-const SMSAuthConfirm = () => {
-    const type = taskReviewType.value
-    if (type === '1') {
-        saveCompleteApprovalTask()
-    } else {
-        batchCompleteApprovalTask()
-    }
-    checkSmsCode()
-}
+//任务审核
+const rowTaskName = () => {
 
-//单个审批
-const saveCompleteApprovalTask = () => {
-    const formData = taskReviewForm.value
-    const DataInfo = taskReviewInfo.value
-    let pid = 'parallelProcessInstanceId';
-    //提交请求
-    SMSAuthLoading.value = true
-    tasksDataApi.saveCompleteApprovalTask({
-        ...formData,
-        taskId: DataInfo['taskId'] || '',
-        parallelProcessInstanceId: DataInfo[pid] || '',
-        formDataId: DataInfo['formDataId'] || '',
-        approvalType: DataInfo['approvalType']
-    }).then(({data}) => {
-        SMSAuthLoading.value = false
-        if (data.code === 200) {
-            SMSAuthShow.value = false
-            showTaskReviewModal.value = false
-            window?.$message?.success('审批成功')
-            getTableData()
-        } else {
-            window?.$message?.warning(data.msg || '审批异常')
-        }
-    }).catch(() => {
-        SMSAuthLoading.value = false
-    })
 }
 
-//批量审批
-const batchCompleteApprovalTask = () => {
-    const rows = checkedRowsRef.value
-    SMSAuthLoading.value = true
-    let taskIds = '',parallelProcessInstanceIds = '';
-    rows.forEach(item => {
-        if (taskIds) {
-            taskIds += `,${item['taskId']}`
-            parallelProcessInstanceIds += `,${item['parallelProcessInstanceId']}`
-        } else {
-            taskIds = item['taskId']
-            parallelProcessInstanceIds = item['parallelProcessInstanceId']
-        }
-    })
-    //发起请求
-    tasksDataApi.batchCompleteApprovalTask({
-        taskIds,
-        parallelProcessInstanceIds,
-        ...taskReviewForm.value
-    }).then(({data}) => {
-        SMSAuthLoading.value = false
-        if (data.code === 200) {
-            SMSAuthShow.value = false
-            showTaskReviewModal.value = false
-            window?.$message?.success('审批成功')
-            getTableData()
-        } else {
-            window?.$message?.error(data.msg || '审批出错')
-        }
-    }).catch(() => {
-        SMSAuthLoading.value = false
-    })
-}
 
 //设置重签规则
 const showSetSignRulesModal = ref(false)
 const setPactVal = ref(true)
 const formReport = ref({date: 1, active: true})
-</script>
-
-<style lang="scss" scoped>
-.hc-layout-box {
-    position: relative;
-    height: calc(100% - 59px);
-    padding: 0 24px 24px;
+const setSignRulesClick = () => {
+    showSetSignRulesModal.value = true
 }
-
-.hc-card-header {
-    position: relative;
-    font-size: initial;
-    font-weight: initial;
+const dateUpdateValue = (val) => {
+    formReport.value.date = val
 }
-.task-review-modal-card .hc-card-body-flex {
-    position: relative;
-    display: flex;
-    width: 100%;
-    height: 100%;
-    .flex-iframe {
-        flex: 1;
-        position: relative;
-        height: 100%;
-        border:1px solid #777;
-        overflow: hidden;
-        margin-right: 24px;
-    }
-    .flex-table {
-        position: relative;
-        width: 40%;
-        height: 100%;
-        .data-table {
-            position: relative;
-            height: calc(100vh - 360px);
-            border: 1px solid #efeff5;
-            border-radius: 3px;
-            overflow: auto;
-        }
-        .action-foot-box {
-            position: absolute;
-            margin-top: 15px;
-            width: 100%;
-            bottom: 0;
-            .radio-group-box .label {
-                margin-right: 15px;
-            }
-            .action-btn-box {
-                position: relative;
-                text-align: center;
-                padding-top: 15px;
-            }
-        }
-        &.vh .data-table {
-            height: 100%;
-        }
-    }
-}
-.obj-item-cell {
-    position: relative;
-    display: flex;
-    align-items: center;
-    margin-top: 24px;
-    .label {
-        margin-right: 20px;
-        width: 126px;
-    }
+//批量审批
+const batchApprovalTaskClick = () => {
+
 }
+</script>
 
+<style lang="scss" scoped>
+@import '../../styles/tasks/hc-data.scss';
 </style>
 
 <style lang="scss">
-.n-modal-container .n-modal-body-wrapper .n-scrollbar .n-scrollbar-container {
-    overflow: initial;
-    .n-modal-scroll-content {
-        width: 100%;
-        height: 100%;
-    }
-}
-.task-review-modal-card {
-    height: 95%;
-    width: 95%;
-    .n-card__content {
-        height: 100%;
-    }
+.hc-layout-box .hc-content-box .hc-card-box.el-card {
+    border-radius: 0 var(--el-card-border-radius) var(--el-card-border-radius) var(--el-card-border-radius);
 }
 </style>

+ 70 - 125
src/views/tasks/message-data.vue

@@ -1,72 +1,72 @@
 <template>
-    <n-divider dashed title-placement="left">消息提醒</n-divider>
     <div class="hc-layout-box">
-        <div class="hc-layout-menu-box">
-            <n-menu :options="menuOptions" v-model:value="menuKey" accordion @update:value="handleMenuValue" :render-extra="renderMenuExtra"/>
+        <div class="hc-layout-left-box">
+            <el-scrollbar>
+                <HcMenuSimple :datas="menuOptions" :keys="menuKey" @change="handleMenuValue"/>
+            </el-scrollbar>
         </div>
         <div class="hc-layout-content-box">
-            <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
+            <HcCard :scrollbar="false" actionSize="lg">
                 <template #header>
-                    <div class="hc-card-header flex items-center">
-                        <div class="w-32">
-                            <n-select v-model:value="searchForm.smsType" :options="smsTypeData" placeholder="消息类型" clearable/>
-                        </div>
-                        <div class="w-96 ml-3">
-                            <n-date-picker v-model:formatted-value="datePickerValue" value-format="yyyy-MM-dd" type="daterange" clearable @update:formatted-value="updateFormattedValue"/>
-                        </div>
-                        <n-button type="primary" class="px-5 ml-3" @click="searchClick">搜索</n-button>
+                    <div class="w-32 ml-2">
+                        <el-select v-model="searchForm.smsType" placeholder="消息类型" clearable>
+                            <el-option v-for="item in smsTypeData" :label="item['label']" :value="item['value']"/>
+                        </el-select>
+                    </div>
+                    <div class="w-64 ml-2">
+                        <HcDatePicker :dates="betweenTime" clearable @change="betweenTimeUpdate"/>
+                    </div>
+                    <div class="ml-2">
+                        <el-button type="primary" @click="searchClick">搜索</el-button>
                     </div>
                 </template>
-                <n-data-table :columns="tableColumns" :data="tableData" :row-key="row => row.id" :pagination="false" :single-line="false" striped @update:checked-row-keys="tableHandleCheck"/>
+                <el-scrollbar>
+                    <div class="hc-table-ref-box">
+                        <el-table hc ref="tableListRef" :data="tableListData" :loading="tableLoading" row-key="id" stripe @selection-change="tableSelectionChange">
+                            <el-table-column type="selection" width="50" />
+                            <el-table-column prop="index" label="序号" width="80">
+                                <template #default="scope">
+                                    {{scope.$index + 1}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="typeValue" label="类型" width="120"/>
+                            <el-table-column prop="startTime" label="日期时间" width="180"/>
+                            <el-table-column prop="endTime" label="内容"/>
+                        </el-table>
+                    </div>
+                </el-scrollbar>
                 <template #action>
-                    <HcPage :pages="searchForm" @change="pageChange"/>
+                    <HcPages :pages="searchForm" @change="pageChange"/>
                 </template>
-            </n-card>
+            </HcCard>
         </div>
     </div>
 </template>
 
 <script setup>
-import {ref,h,watch} from "vue";
-import {useRoute} from 'vue-router'
-import router from '~src/router/index';
-import {useAppStore} from "~src/store/index";
-//import {HcIcon} from "~src/plugins/renderele";
-import HcPage from "~com/plugins/naive/HcPage.vue"
-import {NBadge} from "naive-ui";
+import {ref,onMounted} from "vue";
+import {useAppStore} from "~src/store";
 
-//初始变量
-const useRoutes = useRoute()
+//变量
 const useAppState = useAppStore()
-const routerQuery = useRoutes?.query;
-const MenuBarKey = routerQuery?.MenuBarKey || '';
-const MenuType = routerQuery?.MenuType || 'basic'
-
-//项目合同段信息
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
-const projectInfo = ref(useAppState.getProjectInfo);
-
-//监听
-watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getProjectInfo,
-], ([UserProjectId,UserContractId,UserProjectInfo]) => {
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    projectInfo.value = UserProjectInfo
-})
 
 //左侧菜单
-const menuKey = ref(MenuType)
+const menuKey = ref('basic')
 const menuOptions = ref([
-    {key: 'basic', label: '任务催办', icon: ''},
-    {key: 'password', label: '监测预警', icon: ''},
-    {key: 'project', label: '废除通知', icon: ''},
-    {key: 'log', label: '工单反馈', icon: ''},
-    {key: 'recycle', label: '系统消息', icon: ''},
+    {key: 'basic', label: '任务催办', icon: 'notifications', badge: 10},
+    {key: 'password', label: '监测预警', icon: 'visibility', badge: 10},
+    {key: 'project', label: '废除通知', icon: 'delete', badge: 10},
+    {key: 'log', label: '工单反馈', icon: 'forum', badge: 10},
+    {key: 'recycle', label: '系统消息', icon: 'local_post_office', badge: 10},
 ]);
+const handleMenuValue = (item) => {
+    console.log(item)
+}
+
+//消息类型
+const smsTypeData = ref([{label: "已读消息", value: "1"}, {label: "未读消息", value: "2"}])
 
 //搜索和分页数据
 const searchForm = ref({
@@ -74,98 +74,43 @@ const searchForm = ref({
     current: 1, size: 20, total: 0
 })
 
-//创建标记数量
-const renderMenuExtra = (item) => {
-    //console.log(item)
-    return h(NBadge, {
-        max: 99,
-        value: 100,
-        processing: true,
-    });
-}
-
-//菜单被点击
-const handleMenuValue = (_, item) => {
-    menuKey.value = item.key
-    router.push({
-        path: useRoutes.path,
-        query: {
-            MenuBarKey: MenuBarKey,
-            MenuType: item.key
-        }
-    })
-}
-
-//消息类型
-const smsTypeData = ref([{label: "已读消息", value: "1"}, {label: "未读消息", value: "2"}])
-
-//日期选择处理
-const datePickerValue = ref(null)
-const updateFormattedValue = (val) => {
-    datePickerValue.value = val
-    if (val && val.length > 0) {
-        searchForm.value.startTime = val[0]
-        searchForm.value.endTime = val[1]
-    } else {
-        searchForm.value.startTime = null
-        searchForm.value.endTime = null
-    }
-}
-
-//表格表头
-const tableColumns = [
-    {type: 'selection'},
-    {title: '序号', key: 'num', width: 80, align: 'center',
-        render(_, index) {
-            return index + 1
-        }
-    },
-    {title: '类型', key: 'typeValue', width: 120},
-    {title: '日期时间', key: 'startTime', width: 180},
-    {title: '内容', key: 'endTime'}
-]
-//表格数据
-const tableData = ref([]);
-
-//表格勾选
-const checkedRowsRef = ref([])
-const tableHandleCheck = (_,rows) => {
-    checkedRowsRef.value = rows
+//日期时间被选择
+const betweenTime = ref(null)
+const betweenTimeUpdate = ({val,arr}) => {
+    betweenTime.value = arr
+    searchForm.value.betweenTime = `${val['start']}~${val['end']}`
 }
 
 //搜索
 const searchClick = () => {
-    searchForm.value.current = 1
-    getListTableData()
+    searchForm.value.current = 1;
+    getTableData()
 }
 
 //分页被点击
-const pageChange = (res) => {
-    searchForm.value.current = res.current;
-    searchForm.value.size = res.size;
-    getListTableData()
+const pageChange = ({current, size}) => {
+    searchForm.value.current = current
+    searchForm.value.size = size
+    getTableData()
 }
 
-//获取列表数据
-const getListTableData = () => {
+//获取数据
+const tableLoading = ref(false)
+const tableListData = ref([])
+const getTableData = async () => {
 
 }
 
+//多选
+const tableListRef = ref(null)
+const tableCheckedKeys = ref([]);
+const tableSelectionChange = (rows) => {
+    tableCheckedKeys.value = rows.filter((item) => {
+        return (item??'') !== '';
+    })
+}
 </script>
 
 <style lang="scss" scoped>
 @import "../../styles/tasks/message.scss";
 </style>
-
-<style lang="scss">
-.hc-layout-menu-box {
-    .n-menu .n-menu-item-content .n-menu-item-content-header {
-        position: relative;
-        .n-menu-item-content-header__extra {
-            position: absolute;
-            color: inherit;
-            right: 3px;
-        }
-    }
-}
-</style>

+ 118 - 99
src/views/tasks/sign-admin.vue

@@ -1,107 +1,144 @@
 <template>
-    <n-divider dashed title-placement="left">电签管理员</n-divider>
     <div class="hc-layout-box">
-        <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
+        <HcCard :scrollbar="false" actionSize="lg">
             <template #header>
-                <div class="hc-card-header flex items-center">
-                    <div class="w-32">
-                        <n-select v-model:value="searchForm.tasks" :options="tasksData" placeholder="电签任务人" clearable/>
-                    </div>
-                    <div class="w-32 ml-3">
-                        <n-select v-model:value="searchForm.contract" :options="contractData" placeholder="合同段" clearable/>
-                    </div>
-                    <div class="w-32 ml-3">
-                        <n-select v-model:value="searchForm.status" :options="statusData" placeholder="电签状态" clearable/>
-                    </div>
-                    <div class="w-96 ml-3">
-                        <n-date-picker v-model:value="searchForm.date" type="datetimerange" clearable />
-                    </div>
-                    <div class="w-60 ml-3">
-                        <n-input v-model:value="searchForm.key" type="text" placeholder="请输入关键词" clearable/>
-                    </div>
-                    <n-button type="primary" class="px-5 ml-3">搜索</n-button>
+                <div class="w-32">
+                    <el-select v-model="searchForm.tasks" block clearable size="large" placeholder="电签任务人">
+                        <el-option v-for="item in tasksData" :label="item.dictValue" :value="item.dictKey"/>
+                    </el-select>
+                </div>
+                <div class="w-32 ml-3">
+                    <el-select v-model="searchForm.contract" placeholder="合同段" block clearable size="large" @change="ContractIdChange">
+                        <el-option v-for="item in contractList" :label="item.name" :value="item.id"/>
+                    </el-select>
+                </div>
+                <div class="w-32 ml-3">
+                    <el-select v-model="searchForm.status" block clearable size="large" placeholder="电签状态">
+                        <el-option v-for="item in statusData" :label="item.dictValue" :value="item.dictKey"/>
+                    </el-select>
+                </div>
+                <div class="w-64 ml-3">
+                    <HcDatePicker :dates="betweenTime" size="large" clearable @change="betweenTimeUpdate"/>
+                </div>
+                <div class="w-56 ml-3">
+                    <el-input v-model="searchForm.queryValue" block size="large" placeholder="请输入名称关键词检索" clearable @keyup="keyUpEvent"/>
+                </div>
+                <div class="ml-2">
+                    <el-button type="primary" size="large" @click="searchClick">搜索</el-button>
                 </div>
             </template>
-            <template #header-extra>
-                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_renewal?.textInfo" v-if="btn_renewal">
-                    <template #trigger>
-                        <n-button type="primary" class="px-4">一键重签</n-button>
-                    </template>
-                    <span>{{btn_renewal?.textInfo}}</span>
-                </n-popover>
+            <template #extra>
+                <HcTooltip keys="tasks_sign_key_renewal">
+                    <el-button hc-btn type="primary">
+                        <HcIcon name="border_color"/>
+                        <span>一键重签</span>
+                    </el-button>
+                </HcTooltip>
             </template>
-            <n-data-table :columns="columns" :data="tableData" :pagination="false" :row-key="row => row.name" @update:checked-row-keys="tableHandleCheck" :single-line="false" striped/>
+            <el-scrollbar>
+                <div class="hc-table-ref-box">
+                    <el-table hc ref="tableListRef" :data="tableData" :loading="tableLoading" row-key="id" stripe @selection-change="tableSelectionChange">
+                        <el-table-column type="selection" width="50" />
+                        <el-table-column prop="index" label="序号" width="80">
+                            <template #default="scope">
+                                {{scope.$index + 1}}
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="name" label="流程名称"/>
+                        <el-table-column prop="date" label="任务状态"/>
+                        <el-table-column prop="status" label="电签状态"/>
+                        <el-table-column prop="batch" label="审批时间"/>
+                        <el-table-column prop="person" label="电签失败原因"/>
+                        <el-table-column prop="tesk" label="上报人"/>
+                        <el-table-column prop="tesk1" label="电签任务人"/>
+                    </el-table>
+                </div>
+            </el-scrollbar>
             <template #action>
-                <HcPage :pages="searchForm" @change="pageChange"/>
+                <HcPages :pages="searchForm" @change="pageChange"/>
             </template>
-        </n-card>
+        </HcCard>
     </div>
 </template>
 
 <script setup>
-import {ref,watch} from "vue";
-import {useAppStore} from "~src/store/index";
-import HcPage from "~com/plugins/naive/HcPage.vue"
+import {ref,onMounted} from "vue";
+import {useAppStore} from "~src/store";
+import {getObjValue,  getArrValue} from "vue-utils-plus"
 
-//初始变量
+//变量
 const useAppState = useAppStore()
 const projectId = ref(useAppState.getProjectId);
 const contractId = ref(useAppState.getContractId);
 const projectInfo = ref(useAppState.getProjectInfo);
 
-//按钮气泡开关
-const bubbleVal = ref(useAppState.getBubble);
-
-//监听
-watch(() => [
-    useAppState.getProjectId,
-    useAppState.getContractId,
-    useAppState.getProjectInfo,
-    useAppState.getBubble,
-], ([UserProjectId, UserContractId,UserProjectInfo,Bubble]) => {
-    //项目合同数据
-    projectId.value = UserProjectId
-    contractId.value = UserContractId
-    projectInfo.value = UserProjectInfo
-    //按钮气泡开关
-    bubbleVal.value = Bubble
+//渲染完成
+onMounted(() => {
+    const project = getObjValue(projectInfo.value)
+    contractList.value = getArrValue(project['contractInfoList'])
+    getTableData()
 })
 
-//获取气泡数据
-const getButtonsVal = (value) => {
-    return useAppState.getButtonsVal(value)
-}
-
-//气泡数据
-const btn_renewal = ref(getButtonsVal('tasks_sign_key_renewal'))
+const tasksData = ref([])
+const statusData = ref([])
 
-//电签任务人
-const tasksData = ref([{label: "xxxxxxx张三", value: "song0"}, {label: "xxxxxxx李四", value: "song1"}])
 //合同段
-const contractData = ref([{label: "第一合同段", value: "song0"}, {label: "第二合同段", value: "song1"}, {label: "第三合同段", value: "song2"}])
-//电签状态
-const statusData = ref([{label: "电签中", value: "song0"}, {label: "电签失败", value: "song1"}, {label: "等待电签", value: "song2"}, {label: "电签完成", value: "song3"}])
+const contractList = ref([])
+const ContractIdChange = () => {
+
+}
+
+//日期时间被选择
+const betweenTime = ref(null)
+const betweenTimeUpdate = ({val,arr}) => {
+    betweenTime.value = arr
+    searchForm.value.startTime = val['start']
+    searchForm.value.endTime = val['end']
+}
 
 //搜索表单
-const searchForm = ref({key: null, tasks: null, contract: null, status: null, date: null, current: 1, size: 20, total: 0})
-
-//表格表头
-const columns = [
-    {type: 'selection'},
-    {title: '序号', key: 'num', width: 80, align: 'center',
-        render(_, index) {
-            return index + 1
-        }
-    },
-    {title: '流程名称', key: 'name'},
-    {title: '任务状态', key: 'date'},
-    {title: '电签状态', key: 'status'},
-    {title: '审批时间', key: 'batch'},
-    {title: '电签失败原因', key: 'person'},
-    {title: '上报人', key: 'tesk'},
-    {title: '电签任务人', key: 'tesk1'}
-]
-//表格数据
+const searchForm = ref({
+    queryValue: null, tasks: null, contract: null, status: null, startTime: null, endTime: null,
+    current: 1, size: 20, total: 0
+})
+
+//回车搜索
+const keyUpEvent = (e) => {
+    if (e.key === "Enter") {
+        searchForm.value.current = 1;
+        getTableData()
+    }
+}
+
+//重新搜索数据
+const searchClick = () => {
+    searchForm.value.current = 1
+    getTableData()
+}
+
+//分页被点击
+const pageChange = ({current, size}) => {
+    searchForm.value.current = current
+    searchForm.value.size = size
+    getTableData()
+}
+
+//获取数据
+const tableLoading = ref(false)
+const tableListData = ref([])
+const getTableData = async () => {
+
+}
+
+//多选
+const tableListRef = ref(null)
+const tableCheckedKeys = ref([]);
+const tableSelectionChange = (rows) => {
+    tableCheckedKeys.value = rows.filter((item) => {
+        return (item??'') !== '';
+    })
+}
+
 const tableData = ref([
     { num: 1, name: "test1", date: "已审批-电签失败", status: "电签失败", batch: "2022-05-16 13:35", person: "xxxxx原因", tesk: "李四", tesk1: '张三' },
     { num: 2, name: "test2", date: "已审批-电签中", status: "电签中", batch: "2022-05-16 13:35", person: "xxxxx原因", tesk: "李四", tesk1: '张三'  },
@@ -110,29 +147,11 @@ const tableData = ref([
     { num: 5, name: "test5", date: "xxxxxxxxxx", status: "xxxx", batch: "2022-05-16 13:35", person: "xxxxx原因", tesk: "李四", tesk1: '张三'  },
     { num: 6, name: "test6", date: "xxxxxxxxxx", status: "xxxxxx", batch: "2022-05-16 13:35", person: "xxxxx原因", tesk: "李四", tesk1: '张三'  },
 ]);
-//表格勾选
-const checkedRowKeysRef = ref([])
-const tableHandleCheck = (rowKeys) => {
-    checkedRowKeysRef.value = rowKeys
-}
-
-//分页被点击
-const pageChange = (res) => {
-    searchForm.value.current = res.current;
-    searchForm.value.size = res.size;
-    //getTableData()
-}
 </script>
 
 <style lang="scss" scoped>
 .hc-layout-box {
     position: relative;
-    height: calc(100% - 60px);
-    padding: 0 24px 24px;
-    .hc-card-header {
-        position: relative;
-        font-size: initial;
-        font-weight: initial;
-    }
+    height: 100%;
 }
 </style>

+ 8 - 8
yarn.lock

@@ -475,10 +475,10 @@ electron-to-chromium@^1.4.202:
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz#580ff85b54d7ec0c05f20b1e37ea0becdd7b0ee4"
   integrity sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==
 
-element-plus@^2.2.14:
-  version "2.2.14"
-  resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-2.2.14.tgz#161f2cbf2c12608a570af303f8191c7d7eae725b"
-  integrity sha512-V5Pis0OHhePg1RgVogZrcefaVl8vjVn4Pn9Qsh/t2CbFgjg9kKOYFqf/tuP3ObSXGm3X89hpe0W+nLVAsaFnpw==
+element-plus@^2.2.15:
+  version "2.2.15"
+  resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-2.2.15.tgz#862bb6ecbd15b2d82d79dcf56bbbc30010771132"
+  integrity sha512-SMIx8xKB1YawT9JocyFhbs3Av2rXFfxrCVTLMYS0DK0xnW+fKvwjZngLfwF6MyRzXIuzNW17XFtu0iP3tlJHbA==
   dependencies:
     "@ctrl/tinycolor" "^3.4.1"
     "@element-plus/icons-vue" "^2.0.6"
@@ -1358,10 +1358,10 @@ vue-demi@*:
   resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.6.tgz#f9433cbd75e68a970dec066647f4ba6c08ced48f"
   integrity sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==
 
-vue-router@^4.1.3:
-  version "4.1.3"
-  resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.1.3.tgz#f8dc7931a2253cc5aa9b740f8b98969d08ca283c"
-  integrity sha512-XvK81bcYglKiayT7/vYAg/f36ExPC4t90R/HIpzrZ5x+17BOWptXLCrEPufGgZeuq68ww4ekSIMBZY1qdUdfjA==
+vue-router@^4.1.4:
+  version "4.1.4"
+  resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.1.4.tgz#290540caaf2c54e37a14dec047bd074002eca175"
+  integrity sha512-UgYen33gOtwT3cOG1+yRen+Brk9py8CSlC9LEa3UjvKZ4EAoSo8NjZPDeDnmNerfazorHIJG1NC7qdi1SuQJnQ==
   dependencies:
     "@vue/devtools-api" "^6.1.4"