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

Merge remote-tracking branch 'origin/master'

zzw 1 hónapja
szülő
commit
ae17b30564
25 módosított fájl, 4858 hozzáadás és 994 törlés
  1. 1 0
      .gitignore
  2. 0 0
      .tgitconfig
  3. 4 3
      public/config.js
  4. 9 0
      src/api/audit/collective.js
  5. 18 0
      src/api/audit/taskDraft.js
  6. 9 1
      src/api/auditReviewDocManage.js
  7. 16 0
      src/api/taskCustomizedRelease.js
  8. 84 16
      src/components/task/components/workDraft.vue
  9. 480 7
      src/views/EntDeclaration/auditTaskManagement/components/CostSurveyTab.vue
  10. 8 2
      src/views/EntDeclaration/auditTaskManagement/components/DataRequirementsTab.vue
  11. 763 0
      src/views/EntDeclaration/auditTaskManagement/components/DynamicTableDialog.vue
  12. 858 0
      src/views/EntDeclaration/auditTaskManagement/components/FixedAssetsTable.vue
  13. 690 0
      src/views/EntDeclaration/auditTaskManagement/components/FixedTableDialog.vue
  14. 436 0
      src/views/EntDeclaration/auditTaskManagement/components/SurveyFormDialog.vue
  15. 31 3
      src/views/EntDeclaration/auditTaskManagement/taskFillIn.vue
  16. 267 0
      src/views/costAudit/auditInfo/auditManage/collectiveMain.vue
  17. 26 6
      src/views/costAudit/auditInfo/auditManage/details.vue
  18. 24 21
      src/views/costAudit/auditInfo/auditManage/submitData.vue
  19. 213 15
      src/views/costAudit/auditInfo/auditManage/workDraft.vue
  20. 22 488
      src/views/costAudit/projectInfo/auditProjectManage/memoManage/index.vue
  21. 480 0
      src/views/costAudit/projectInfo/auditProjectManage/memoManage/memoManage.scss
  22. 19 14
      src/views/costAudit/projectInfo/auditProjectManage/memoManage/memoManageMixin.js
  23. 252 131
      src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/auditNoticeTab.vue
  24. 2 2
      src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/index.js
  25. 146 285
      src/views/home/index.vue

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 node_modules
+.idea/

+ 0 - 0
.tgitconfig


+ 4 - 3
public/config.js

@@ -4,9 +4,9 @@
 // var host = 'http://116.204.117.33' //基本用这个
 //var host = 'http://116.204.117.33' // 测试
 // var host = 'http://b463f4b7.natappfree.cc' // 后端服务海鹏
-var host = 'http://5jrgep.ipx.wanziwk.cn' // 后端服务译文
-// var host = 'http://192.168.1.2' // 后端服务译文
-// var host = 'http://5jrgep.ipx.wanziwk.cn'
+// var host = 'http://5jrgep.ipx.wanziwk.cn' // 后端服务译文
+// var host = 'http://192.168.1.144' // 后端服务译文
+var host = 'http://5jrgep.ipx.wanziwk.cn'
 // combine为true时五合一部署, 为false时分五个服务部署
 var combine = true
 // var gateway = '8280/stage-api'
@@ -30,6 +30,7 @@ window.getModuleRootUrl = function (module) {
     modulePort = defaultModulePortMap[module]
   }
   return "http://5jrgep.ipx.wanziwk.cn";
+  //return host + ':' + modulePort
   // return host + modulePort
 }
 window.context = {

+ 9 - 0
src/api/audit/collective.js

@@ -39,3 +39,12 @@ export function deleteCollectiveDeliberate(id) {
     method: 'delete',
   })
 }
+
+// 获取子单位列表
+export function getSubUnitList(data) {
+  return request({
+    url: url + '/api/enterprise/castTask/getChildTaskUnits',
+    method: 'get',
+    params: data,
+  })
+}

+ 18 - 0
src/api/audit/taskDraft.js

@@ -24,3 +24,21 @@ export function deleteTaskDraft(data) {
     method: 'post',
   })
 }
+
+// 获取工作底稿在线编辑内容
+export function getTaskDraftOnlineEdit(data) {
+  return request({
+    url: url + '/api/enterprise/taskDraft/getByTaskId',
+    method: 'get',
+    params: data,
+  })
+}
+
+// 保存工作底稿在线编辑内容
+export function saveTaskDraftOnlineEdit(data) {
+  return request({
+    url: url + '/api/enterprise/taskDraft/save',
+    method: 'post',
+    data: data,
+  })
+}

+ 9 - 1
src/api/auditReviewDocManage.js

@@ -60,7 +60,7 @@ export function getDocumentTemplateById(id) {
     method: 'get',
   })
 }
-// 根据ID查询数据项
+// 根据文书id查询数据项
 export function queryByDocumentId(params) {
   return request({
     url: url + `/costDocumentTemplateFile/v1/queryByDocumentId`,
@@ -68,3 +68,11 @@ export function queryByDocumentId(params) {
     params,
   })
 }
+// 根据文书id查询和whereValue查询
+export function queryByDocumentIdandWhereValue(params) {
+  return request({
+    url: url + `/costDocumentTemplateFile/v1/queryByDocumentIdandWhereValue`,
+    method: 'get',
+    params,
+  })
+}

+ 16 - 0
src/api/taskCustomizedRelease.js

@@ -233,6 +233,22 @@ export function deleteCostProjectDocument(id) {
     method: 'delete',
   })
 }
+// 更新扫描文件
+export function updateScan(data) {
+  return request({
+    url: `${url}/api/costProjectDocument/v1/updateScan`,
+    method: 'post',
+    data,
+  })
+}
+// 根据id生成文书并且下载
+export function downDocument(params) {
+  return request({
+    url: `${url}/api/costProjectDocument/v1/downDocument`,
+    method: 'get',
+    params,
+  })
+}
 /**
  * 根据流程节id获取节点模板数据
  */

+ 84 - 16
src/components/task/components/workDraft.vue

@@ -1,14 +1,19 @@
 <template>
   <div class="work-draft-container">
-    <ht-editor
-      v-model="workingPaperContent"
-      class="working-paper-editor"
-      height="500px"
-      width="100%"
-      :config="editorConfig"
-      :disabled="disabled"
-      @ready="onEditorReady"
-    />
+    <div class="editor-header">
+      <span class="editor-title">工作底稿在线编辑:</span>
+    </div>
+    <div class="editor-wrapper">
+      <ht-editor
+        v-model="workingPaperContent"
+        class="working-paper-editor"
+        height="500px"
+        width="100%"
+        :config="editorConfig"
+        :disabled="disabled"
+        @ready="onEditorReady"
+      />
+    </div>
     <!-- 工作底稿列表 -->
     <!-- <div>
       <el-button
@@ -188,6 +193,7 @@
     getTaskDraftList,
     addTaskDraft,
     deleteTaskDraft,
+    getTaskDraftOnlineEdit,
   } from '@/api/audit/taskDraft'
   import { uploadFile } from '@/api/file'
   export default {
@@ -212,7 +218,7 @@
           excludeMenus: ['image', 'video'],
         },
         // 工作底稿数据
-        workingPaperContent: '工作底稿内容将在这里展示。',
+        workingPaperContent: '',
         // 工作底稿记录列表
         workingPaperRecords: [],
         // 工作底稿弹窗
@@ -244,8 +250,22 @@
         },
       }
     },
+    watch: {
+      id: {
+        handler(newVal) {
+          if (newVal) {
+            this.getWorkingPaperRecords()
+            this.getWorkingPaperContent()
+          }
+        },
+        immediate: true,
+      },
+    },
     mounted() {
-      this.getWorkingPaperRecords()
+      if (this.id) {
+        this.getWorkingPaperRecords()
+        this.getWorkingPaperContent()
+      }
     },
     methods: {
       // 获取工作底稿列表
@@ -299,6 +319,25 @@
         console.log('编辑器已就绪', editor)
         // 可以在这里获取编辑器实例,进行更多操作
       },
+      // 获取工作底稿在线编辑内容
+      async getWorkingPaperContent() {
+        if (!this.id) {
+          return
+        }
+        try {
+          const res = await getTaskDraftOnlineEdit({ taskId: this.id })
+          if (res && res.code === 200 && res.value) {
+            // 回显内容到编辑器
+            this.workingPaperContent = res.value.content || ''
+          } else {
+            // 如果没有数据,初始化为空
+            this.workingPaperContent = ''
+          }
+        } catch (error) {
+          console.error('获取工作底稿在线编辑内容失败:', error)
+          this.workingPaperContent = ''
+        }
+      },
       // 工作底稿操作
       handleAddWorkingPaper() {
         this.isEditWorkingPaper = false
@@ -684,12 +723,41 @@
   }
 </script>
 
-<style scoped>
-  /* .work-draft-container {
-    padding: 20px;
-  } */
+<style scoped lang="scss">
+  .work-draft-container {
+    width: 100%;
+  }
 
-  .working-paper-editor {
+  .editor-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+  }
+
+  .editor-title {
+    font-size: 16px;
+    font-weight: bold;
+  }
+
+  .editor-wrapper {
+    width: 100%;
     margin-bottom: 20px;
   }
+
+  .working-paper-editor {
+    width: 100% !important;
+  }
+
+  :deep(.inputs.ht-form-inputs__inline) {
+    width: 100%;
+  }
+
+  :deep(.ht-editor) {
+    width: 100% !important;
+  }
+
+  :deep(.ht-container) {
+    width: 100% !important;
+  }
 </style>

+ 480 - 7
src/views/EntDeclaration/auditTaskManagement/components/CostSurveyTab.vue

@@ -1,5 +1,34 @@
 <template>
   <div>
+    <!-- 调查表填报弹窗(单记录类型) -->
+    <survey-form-dialog
+      :visible.sync="surveyFormDialogVisible"
+      :survey-data="currentSurveyRow"
+      :form-fields="formFields"
+      :is-view-mode="isViewMode"
+      @save="handleSurveyFormSave"
+    />
+
+    <!-- 固定表填报弹窗 -->
+    <fixed-table-dialog
+      :visible.sync="fixedTableDialogVisible"
+      :survey-data="currentSurveyRow"
+      :table-items="tableItems"
+      :audit-periods="auditPeriods"
+      :is-view-mode="isViewMode"
+      @save="handleFixedTableSave"
+    />
+
+    <!-- 动态表填报弹窗 -->
+    <dynamic-table-dialog
+      :visible.sync="dynamicTableDialogVisible"
+      :survey-data="currentSurveyRow"
+      :table-data="dynamicTableData"
+      :table-items="tableItems"
+      :is-view-mode="isViewMode"
+      @save="handleDynamicTableSave"
+    />
+
     <el-table
       style="width: 100%; margin-top: 20px"
       :data="paginatedData"
@@ -7,12 +36,11 @@
       size="medium"
     >
       <!-- 序号列 -->
-      <el-table-column
-        prop="index"
-        label="序号"
-        width="60"
-        align="center"
-      ></el-table-column>
+      <el-table-column prop="index" label="序号" width="60" align="center">
+        <template slot-scope="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
       <el-table-column label="成本调查表" min-width="220">
         <template slot-scope="scope">
           <span
@@ -74,6 +102,14 @@
               type="text"
               size="small"
               :disabled="isViewMode"
+              @click="handleOnlineFillClick(scope.row)"
+            >
+              在线填报
+            </el-button>
+            <el-button
+              type="text"
+              size="small"
+              :disabled="isViewMode"
               @click="$emit('handle-modify', scope.row)"
             >
               修改
@@ -100,7 +136,7 @@
               type="text"
               size="small"
               :disabled="isViewMode"
-              @click="$emit('handle-online-fill', scope.row)"
+              @click="handleOnlineFillClick(scope.row)"
             >
               在线填报
             </el-button>
@@ -140,8 +176,17 @@
 </template>
 
 <script>
+  import SurveyFormDialog from './SurveyFormDialog.vue'
+  import FixedTableDialog from './FixedTableDialog.vue'
+  import DynamicTableDialog from './DynamicTableDialog.vue'
+
   export default {
     name: 'CostSurveyTab',
+    components: {
+      SurveyFormDialog,
+      FixedTableDialog,
+      DynamicTableDialog,
+    },
     props: {
       paginatedData: {
         type: Array,
@@ -156,5 +201,433 @@
         default: false,
       },
     },
+    data() {
+      return {
+        surveyFormDialogVisible: false,
+        fixedTableDialogVisible: false,
+        dynamicTableDialogVisible: false,
+        currentSurveyRow: null,
+        // 表单字段配置(可以从后台获取,或通过 props 传入)
+        formFields: [],
+        // 固定表数据配置
+        tableItems: [],
+        // 监审期间(年份数组)
+        auditPeriods: [],
+        // 动态表数据
+        dynamicTableData: [],
+      }
+    },
+    mounted() {
+      // 如果当前行有表单配置,则使用,否则使用默认配置
+      // 这里可以根据实际需求从后台获取表单配置
+      this.initFormFields()
+    },
+    methods: {
+      // 处理在线填报点击
+      handleOnlineFillClick(row) {
+        this.currentSurveyRow = row
+
+        // 如果表格类型是"单记录",弹出调查表填报弹窗
+        if (row.tableType === '单记录') {
+          // 初始化表单字段配置
+          this.initFormFields()
+          this.surveyFormDialogVisible = true
+        } else if (row.tableType === '固定表') {
+          // 如果表格类型是"固定表",弹出固定表填报弹窗
+          this.initFixedTableData()
+          this.fixedTableDialogVisible = true
+        } else if (row.tableType === '动态表') {
+          // 如果表格类型是"动态表",弹出动态表填报弹窗
+          this.initDynamicTableData()
+          this.dynamicTableDialogVisible = true
+        } else {
+          // 其他类型,触发原有事件
+          this.$emit('handle-online-fill', row)
+        }
+      },
+      // 处理调查表保存
+      handleSurveyFormSave(formData) {
+        // 可以将保存的数据传递给父组件
+        this.$emit('handle-survey-form-save', {
+          row: this.currentSurveyRow,
+          formData: formData,
+        })
+      },
+      // 处理固定表保存
+      handleFixedTableSave(tableData) {
+        // 可以将保存的数据传递给父组件
+        this.$emit('handle-fixed-table-save', {
+          row: this.currentSurveyRow,
+          tableData: tableData,
+        })
+      },
+      // 处理动态表保存
+      handleDynamicTableSave(tableData) {
+        // 可以将保存的数据传递给父组件
+        this.$emit('handle-dynamic-table-save', {
+          row: this.currentSurveyRow,
+          tableData: tableData,
+        })
+      },
+      // 初始化动态表数据
+      initDynamicTableData() {
+        // 如果当前行有动态表数据,则使用
+        if (this.currentSurveyRow && this.currentSurveyRow.dynamicTableData) {
+          this.dynamicTableData = this.currentSurveyRow.dynamicTableData
+        } else {
+          // 使用空数组,组件内部会使用假数据
+          this.dynamicTableData = []
+        }
+
+        // 初始化表格项配置(用于详情/编辑时显示表单)
+        if (this.currentSurveyRow && this.currentSurveyRow.tableItems) {
+          this.tableItems = this.currentSurveyRow.tableItems
+        } else {
+          // 使用固定表的假数据配置
+          this.tableItems = this.getMockTableItems()
+        }
+      },
+      // 初始化表单字段配置
+      initFormFields() {
+        // 如果当前行有表单配置,则使用
+        // 这里可以根据实际需求从后台获取表单配置
+        // 例如:从 currentSurveyRow 中获取表单配置,或调用 API 获取
+        if (this.currentSurveyRow && this.currentSurveyRow.formFields) {
+          this.formFields = this.currentSurveyRow.formFields
+        } else {
+          // 使用假数据作为测试(实际开发中应该从后台获取)
+          this.formFields = this.getMockFormFields()
+        }
+      },
+      // 获取假数据表单字段配置(用于测试)
+      getMockFormFields() {
+        return [
+          {
+            prop: 'institutionName',
+            label: '机构名称',
+            type: 'input',
+            colSpan: 12,
+            defaultValue: '幼儿园基本情况',
+            placeholder: '请输入机构名称',
+            required: true,
+          },
+          {
+            prop: 'institutionNature',
+            label: '机构性质',
+            type: 'select',
+            colSpan: 12,
+            dictType: 'institutionNature', // 字典类型
+            defaultValue: '公办',
+            placeholder: '请选择机构性质',
+            required: true,
+            clearable: true,
+          },
+          {
+            prop: 'institutionLevel',
+            label: '机构评定等级',
+            type: 'select',
+            colSpan: 12,
+            dictType: 'institutionLevel', // 字典类型
+            defaultValue: '省一级',
+            placeholder: '请选择机构评定等级',
+            required: true,
+            clearable: true,
+          },
+          {
+            prop: 'educationMode',
+            label: '机构办学方式',
+            type: 'select',
+            colSpan: 12,
+            dictType: 'educationMode', // 字典类型
+            defaultValue: '全日制',
+            placeholder: '请选择机构办学方式',
+            required: true,
+            clearable: true,
+          },
+          {
+            prop: 'institutionAddress',
+            label: '机构地址',
+            type: 'input',
+            colSpan: 12,
+            placeholder: '请输入机构地址',
+            required: true,
+          },
+          {
+            prop: 'formFiller',
+            label: '机构填表人',
+            type: 'input',
+            colSpan: 12,
+            placeholder: '请输入机构填表人',
+            required: true,
+          },
+          {
+            prop: 'financialManager',
+            label: '机构财务负责人',
+            type: 'input',
+            colSpan: 12,
+            placeholder: '请输入机构财务负责人',
+            required: true,
+          },
+          {
+            prop: 'contactPhone',
+            label: '机构联系电话',
+            type: 'input',
+            colSpan: 12,
+            placeholder: '请输入机构联系电话',
+            required: true,
+            rules: [
+              {
+                required: true,
+                message: '请输入机构联系电话',
+                trigger: 'blur',
+              },
+              {
+                pattern: /^1[3-9]\d{9}$/,
+                message: '请输入正确的手机号码',
+                trigger: 'blur',
+              },
+            ],
+          },
+        ]
+      },
+      // 初始化固定表数据
+      initFixedTableData() {
+        // 如果当前行有表格配置,则使用
+        if (this.currentSurveyRow && this.currentSurveyRow.tableItems) {
+          this.tableItems = this.currentSurveyRow.tableItems
+        } else {
+          // 使用假数据作为测试(实际开发中应该从后台获取)
+          this.tableItems = this.getMockTableItems()
+        }
+
+        // 初始化监审期间
+        if (this.currentSurveyRow && this.currentSurveyRow.auditPeriod) {
+          this.auditPeriods = this.parseAuditPeriod(
+            this.currentSurveyRow.auditPeriod
+          )
+        } else {
+          // 默认使用最近3年
+          const currentYear = new Date().getFullYear()
+          this.auditPeriods = [
+            String(currentYear - 2),
+            String(currentYear - 1),
+            String(currentYear),
+          ]
+        }
+      },
+      // 解析监审期间字符串(如 "2022,2023,2024" 或 "2022-2024")
+      parseAuditPeriod(periodStr) {
+        if (!periodStr) return []
+        if (periodStr.includes(',')) {
+          return periodStr.split(',').map((p) => p.trim())
+        }
+        if (periodStr.includes('-')) {
+          const parts = periodStr.split('-')
+          if (parts.length === 2) {
+            const start = parseInt(parts[0].trim())
+            const end = parseInt(parts[1].trim())
+            const years = []
+            for (let year = start; year <= end; year++) {
+              years.push(String(year))
+            }
+            return years
+          }
+        }
+        return [String(periodStr)]
+      },
+      // 获取假数据表格配置(用于测试)
+      getMockTableItems() {
+        return [
+          {
+            id: '1',
+            itemName: '班级数',
+            unit: '个',
+            isCategory: false,
+            seq: 1,
+            validateRules: {
+              required: true,
+              type: 'number',
+              min: 0,
+            },
+          },
+          {
+            id: '2',
+            itemName: '幼儿学生人数',
+            unit: '人',
+            isCategory: false,
+            seq: 2,
+            validateRules: {
+              required: true,
+              type: 'number',
+              min: 0,
+            },
+          },
+          {
+            id: 'III',
+            itemName: '在取做保职工总人数',
+            unit: '人',
+            isCategory: true,
+            categorySeq: 'III',
+            children: [
+              {
+                id: '3-1',
+                itemName: '行政管理人员数',
+                unit: '人',
+                isCategory: false,
+                categoryId: 'III',
+                seq: 3,
+                validateRules: {
+                  required: true,
+                  type: 'number',
+                  min: 0,
+                },
+                linkageRules: {
+                  parent: 'III',
+                  relation: 'sum',
+                },
+              },
+              {
+                id: '3-2',
+                itemName: '教师人数',
+                unit: '人',
+                isCategory: false,
+                categoryId: 'III',
+                seq: 4,
+                validateRules: {
+                  required: true,
+                  type: 'number',
+                  min: 0,
+                },
+                linkageRules: {
+                  parent: 'III',
+                  relation: 'sum',
+                },
+              },
+              {
+                id: '3-3',
+                itemName: '保育员人数',
+                unit: '人',
+                isCategory: false,
+                categoryId: 'III',
+                seq: 5,
+                validateRules: {
+                  required: true,
+                  type: 'number',
+                  min: 0,
+                },
+                linkageRules: {
+                  parent: 'III',
+                  relation: 'sum',
+                },
+              },
+              {
+                id: '3-4',
+                itemName: '医务人员',
+                unit: '人',
+                isCategory: false,
+                categoryId: 'III',
+                seq: 6,
+                validateRules: {
+                  required: true,
+                  type: 'number',
+                  min: 0,
+                },
+                linkageRules: {
+                  parent: 'III',
+                  relation: 'sum',
+                },
+              },
+              {
+                id: '3-5',
+                itemName: '工勤人员',
+                unit: '人',
+                isCategory: false,
+                categoryId: 'III',
+                seq: 7,
+                validateRules: {
+                  required: true,
+                  type: 'number',
+                  min: 0,
+                },
+                linkageRules: {
+                  parent: 'III',
+                  relation: 'sum',
+                },
+                children: [
+                  {
+                    id: '3-5-1',
+                    itemName: '炊事员',
+                    unit: '人',
+                    isCategory: false,
+                    categoryId: '3-5',
+                    seq: 8,
+                    validateRules: {
+                      required: true,
+                      type: 'number',
+                      min: 0,
+                    },
+                    linkageRules: {
+                      parent: '3-5',
+                      relation: 'sum',
+                    },
+                  },
+                  {
+                    id: '3-5-2',
+                    itemName: '司机',
+                    unit: '人',
+                    isCategory: false,
+                    categoryId: '3-5',
+                    seq: 9,
+                    validateRules: {
+                      required: true,
+                      type: 'number',
+                      min: 0,
+                    },
+                    linkageRules: {
+                      parent: '3-5',
+                      relation: 'sum',
+                    },
+                  },
+                  {
+                    id: '3-5-3',
+                    itemName: '清洁工',
+                    unit: '人',
+                    isCategory: false,
+                    categoryId: '3-5',
+                    seq: 10,
+                    validateRules: {
+                      required: true,
+                      type: 'number',
+                      min: 0,
+                    },
+                    linkageRules: {
+                      parent: '3-5',
+                      relation: 'sum',
+                    },
+                  },
+                ],
+              },
+              {
+                id: '3-6',
+                itemName: '其他人员',
+                unit: '人',
+                isCategory: false,
+                categoryId: 'III',
+                seq: 11,
+                validateRules: {
+                  required: true,
+                  type: 'number',
+                  min: 0,
+                },
+                linkageRules: {
+                  parent: 'III',
+                  relation: 'sum',
+                },
+              },
+            ],
+          },
+        ]
+      },
+    },
   }
 </script>

+ 8 - 2
src/views/EntDeclaration/auditTaskManagement/components/DataRequirementsTab.vue

@@ -127,7 +127,10 @@
                 下载
               </el-button>
               <el-button
-                v-if="scope.row.auditedStatus !== '1' && currentNode === 'clcs'"
+                v-if="
+                  scope.row.auditedStatus !== '1' &&
+                  (currentNode === 'clcs' || currentNode === 'tjcl')
+                "
                 type="text"
                 size="small"
                 :disabled="isViewMode"
@@ -146,7 +149,10 @@
                 模版下载
               </el-button>
               <el-button
-                v-if="scope.row.auditedStatus !== '1' && currentNode === 'clcs'"
+                v-if="
+                  scope.row.auditedStatus !== '1' &&
+                  (currentNode === 'clcs' || currentNode === 'tjcl')
+                "
                 type="text"
                 size="small"
                 :disabled="isViewMode"

+ 763 - 0
src/views/EntDeclaration/auditTaskManagement/components/DynamicTableDialog.vue

@@ -0,0 +1,763 @@
+<template>
+  <el-dialog
+    title="调查表填报"
+    :visible.sync="dialogVisible"
+    width="90%"
+    :close-on-click-modal="false"
+    :show-close="true"
+    append-to-body
+    :modal="false"
+    @close="handleClose"
+  >
+    <!-- 操作按钮 -->
+    <div class="action-buttons" style="margin-bottom: 20px">
+      <el-button type="primary" :disabled="isViewMode" @click="handleAdd">
+        <i class="el-icon-plus"></i>
+        新增
+      </el-button>
+      <el-button
+        type="danger"
+        :disabled="isViewMode || selectedRows.length === 0"
+        @click="handleBatchDelete"
+      >
+        <i class="el-icon-delete"></i>
+        删除
+      </el-button>
+    </div>
+
+    <!-- 数据表格 -->
+    <el-table
+      :data="paginatedTableData"
+      border
+      style="width: 100%"
+      @selection-change="handleSelectionChange"
+    >
+      <!-- 复选框列 -->
+      <el-table-column type="selection" width="55" align="center" />
+
+      <!-- 序号列 -->
+      <el-table-column prop="seq" label="序号" width="80" align="center">
+        <template slot-scope="scope">
+          {{ getRowIndex(scope.$index) }}
+        </template>
+      </el-table-column>
+
+      <!-- 监审期间列 -->
+      <el-table-column
+        prop="auditPeriod"
+        label="监审期间"
+        min-width="150"
+        align="center"
+      >
+        <template slot-scope="scope">
+          {{ scope.row.auditPeriod }}
+        </template>
+      </el-table-column>
+
+      <!-- 填报时间列 -->
+      <el-table-column
+        prop="fillTime"
+        label="填报时间"
+        width="180"
+        align="center"
+      >
+        <template slot-scope="scope">
+          {{ scope.row.fillTime }}
+        </template>
+      </el-table-column>
+
+      <!-- 最后修改时间列 -->
+      <el-table-column
+        prop="lastModifyTime"
+        label="最后修改时间"
+        width="180"
+        align="center"
+      >
+        <template slot-scope="scope">
+          {{ scope.row.lastModifyTime }}
+        </template>
+      </el-table-column>
+
+      <!-- 操作列 -->
+      <el-table-column label="操作" width="200" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            type="text"
+            size="small"
+            :disabled="isViewMode"
+            @click="handleViewDetail(scope.row)"
+          >
+            详情
+          </el-button>
+          <el-button
+            type="text"
+            size="small"
+            :disabled="isViewMode"
+            @click="handleEdit(scope.row)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            type="text"
+            size="small"
+            :disabled="isViewMode"
+            style="color: #f56c6c"
+            @click="handleDelete(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <el-pagination
+      background
+      layout="total, prev, pager, next, jumper"
+      :current-page="pagination.currentPage"
+      :page-size="pagination.pageSize"
+      :total="pagination.total"
+      style="margin-top: 20px; text-align: right"
+      @current-change="handlePageChange"
+      @size-change="handleSizeChange"
+    />
+
+    <!-- 详情/编辑弹窗 -->
+    <el-dialog
+      :title="detailDialogTitle"
+      :visible.sync="detailDialogVisible"
+      width="90%"
+      :close-on-click-modal="false"
+      append-to-body
+      :modal="false"
+    >
+      <div>
+        <!-- <div style="margin-bottom: 20px; padding: 10px; background: #f5f7fa">
+          <p><strong>监审期间:</strong>{{ currentRow.auditPeriod }}</p>
+          <p><strong>填报时间:</strong>{{ currentRow.fillTime }}</p>
+          <p><strong>最后修改时间:</strong>{{ currentRow.lastModifyTime }}</p>
+        </div> -->
+        <!-- 固定资产表格 -->
+        <fixed-assets-table
+          ref="fixedAssetsTable"
+          :table-items="localTableItems"
+          :saved-data="currentRow ? currentRow.data || {} : {}"
+          :is-view-mode="!isEditMode"
+        />
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button v-if="isEditMode" type="primary" @click="handleSaveDetail">
+          保存
+        </el-button>
+        <el-button @click="detailDialogVisible = false">关闭</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- <div slot="footer" class="dialog-footer">
+      <el-button @click="handleCancel">取消</el-button>
+    </div> -->
+  </el-dialog>
+</template>
+
+<script>
+  import { Message, MessageBox } from 'element-ui'
+  import FixedAssetsTable from './FixedAssetsTable.vue'
+
+  export default {
+    name: 'DynamicTableDialog',
+    components: {
+      FixedAssetsTable,
+    },
+    props: {
+      visible: {
+        type: Boolean,
+        default: false,
+      },
+      surveyData: {
+        type: Object,
+        default: () => ({}),
+      },
+      // 表格数据
+      tableData: {
+        type: Array,
+        default: () => [],
+      },
+      // 表格项配置(用于详情/编辑时显示表单)
+      tableItems: {
+        type: Array,
+        default: () => [],
+      },
+      // 是否查看模式
+      isViewMode: {
+        type: Boolean,
+        default: false,
+      },
+    },
+    data() {
+      return {
+        dialogVisible: false,
+        // 表格数据
+        localTableData: [],
+        // 选中的行
+        selectedRows: [],
+        // 分页配置
+        pagination: {
+          currentPage: 1,
+          pageSize: 10,
+          total: 0,
+        },
+        // 详情/编辑弹窗
+        detailDialogVisible: false,
+        detailDialogTitle: '详情',
+        currentRow: null,
+        isEditMode: false,
+        // 表格项配置(本地)
+        localTableItems: [],
+      }
+    },
+    computed: {
+      // 分页后的表格数据
+      paginatedTableData() {
+        const start =
+          (this.pagination.currentPage - 1) * this.pagination.pageSize
+        const end = start + this.pagination.pageSize
+        return this.localTableData.slice(start, end)
+      },
+    },
+    watch: {
+      visible: {
+        handler(newVal) {
+          this.dialogVisible = newVal
+          if (newVal) {
+            this.initTableData()
+            this.initTableItems()
+          }
+        },
+        immediate: true,
+      },
+      tableItems: {
+        handler(newVal) {
+          this.initTableItems()
+        },
+        deep: true,
+      },
+      dialogVisible(newVal) {
+        if (!newVal) {
+          this.$emit('update:visible', false)
+        }
+      },
+      tableData: {
+        handler(newVal) {
+          this.initTableData()
+        },
+        deep: true,
+      },
+    },
+    methods: {
+      // 初始化表格项配置
+      initTableItems() {
+        // if (this.tableItems && this.tableItems.length > 0) {
+        //   this.localTableItems = [...this.tableItems]
+        // } else {
+        //   // 使用假数据
+        //   this.localTableItems = this.getMockTableItems()
+        // }
+        this.localTableItems = this.getMockTableItems()
+      },
+      // 获取假数据表格项配置(用于测试)
+      getMockTableItems() {
+        return [
+          {
+            id: 'I',
+            itemName: '房屋建筑物',
+            isCategory: true,
+            categorySeq: 'I',
+            children: [
+              {
+                id: 'I-1',
+                itemName: '办公用房',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'I-2',
+                itemName: '教保用房',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'I-3',
+                itemName: '幼儿宿舍用房',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'I-4',
+                itemName: '其它',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'II',
+            itemName: '交通运输工具',
+            isCategory: true,
+            categorySeq: 'II',
+            children: [
+              {
+                id: 'II-1',
+                itemName: '车辆',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'III',
+            itemName: '教保专用设备',
+            isCategory: true,
+            categorySeq: 'III',
+            children: [
+              {
+                id: 'III-1',
+                itemName: '电教',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'III-2',
+                itemName: '文体',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'IV',
+            itemName: '办公设备',
+            isCategory: true,
+            categorySeq: 'IV',
+            children: [
+              {
+                id: 'IV-1',
+                itemName: '电脑',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'V',
+            itemName: '其它固定资产',
+            isCategory: true,
+            categorySeq: 'V',
+            children: [
+              {
+                id: 'V-1',
+                itemName: '空调',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-2',
+                itemName: '家电',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-3',
+                itemName: '供水系统',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-4',
+                itemName: '洗涤用具',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-5',
+                itemName: '家具',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-6',
+                itemName: '炊事用具',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-7',
+                itemName: '其它',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+        ]
+      },
+      // 初始化表格数据
+      initTableData() {
+        if (this.tableData && this.tableData.length > 0) {
+          this.localTableData = [...this.tableData]
+        } else {
+          // 使用假数据
+          this.localTableData = this.getMockTableData()
+        }
+        this.pagination.total = this.localTableData.length
+        this.pagination.currentPage = 1
+      },
+      // 获取假数据(用于测试)
+      getMockTableData() {
+        const currentDate = new Date()
+        const formatDateTime = (date) => {
+          const year = date.getFullYear()
+          const month = String(date.getMonth() + 1).padStart(2, '0')
+          const day = String(date.getDate()).padStart(2, '0')
+          const hours = String(date.getHours()).padStart(2, '0')
+          const minutes = String(date.getMinutes()).padStart(2, '0')
+          const seconds = String(date.getSeconds()).padStart(2, '0')
+          return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+        }
+
+        const data = []
+        const currentYear = currentDate.getFullYear()
+
+        // 生成25条假数据
+        for (let i = 0; i < 25; i++) {
+          const year = currentYear - i
+          const fillDate = new Date(currentDate)
+          fillDate.setDate(fillDate.getDate() - i)
+          const modifyDate = new Date(fillDate)
+          modifyDate.setHours(modifyDate.getHours() + 1)
+
+          data.push({
+            id: `row-${i + 1}`,
+            seq: i + 1,
+            auditPeriod: `${year}`,
+            fillTime: formatDateTime(fillDate),
+            lastModifyTime: formatDateTime(modifyDate),
+            data: {}, // 存储具体的填报数据
+          })
+        }
+
+        return data
+      },
+      // 获取行索引(考虑分页)
+      getRowIndex(index) {
+        return (
+          (this.pagination.currentPage - 1) * this.pagination.pageSize +
+          index +
+          1
+        )
+      },
+      // 选择变化
+      handleSelectionChange(selection) {
+        this.selectedRows = selection
+      },
+      // 新增
+      handleAdd() {
+        const currentYear = new Date().getFullYear()
+        const currentDate = new Date()
+        const formatDateTime = (date) => {
+          const year = date.getFullYear()
+          const month = String(date.getMonth() + 1).padStart(2, '0')
+          const day = String(date.getDate()).padStart(2, '0')
+          const hours = String(date.getHours()).padStart(2, '0')
+          const minutes = String(date.getMinutes()).padStart(2, '0')
+          const seconds = String(date.getSeconds()).padStart(2, '0')
+          return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+        }
+
+        const newRow = {
+          id: `row-${Date.now()}`,
+          seq: this.localTableData.length + 1,
+          auditPeriod: String(currentYear),
+          fillTime: formatDateTime(currentDate),
+          lastModifyTime: formatDateTime(currentDate),
+          data: {},
+        }
+
+        this.localTableData.unshift(newRow)
+        this.pagination.total = this.localTableData.length
+        this.pagination.currentPage = 1
+
+        // 打开编辑弹窗
+        this.currentRow = newRow
+        this.isEditMode = true
+        this.detailDialogTitle = '编辑'
+        this.detailDialogVisible = true
+
+        Message.success('新增成功,请填写数据')
+      },
+      // 批量删除
+      handleBatchDelete() {
+        if (this.selectedRows.length === 0) {
+          Message.warning('请选择要删除的记录')
+          return
+        }
+
+        MessageBox.confirm(
+          `确定要删除选中的 ${this.selectedRows.length} 条记录吗?`,
+          '提示',
+          {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          }
+        )
+          .then(() => {
+            const selectedIds = this.selectedRows.map((row) => row.id)
+            this.localTableData = this.localTableData.filter(
+              (row) => !selectedIds.includes(row.id)
+            )
+            this.pagination.total = this.localTableData.length
+
+            // 如果当前页没有数据了,跳转到上一页
+            if (
+              this.paginatedTableData.length === 0 &&
+              this.pagination.currentPage > 1
+            ) {
+              this.pagination.currentPage--
+            }
+
+            this.selectedRows = []
+            Message.success('删除成功')
+          })
+          .catch(() => {})
+      },
+      // 查看详情
+      handleViewDetail(row) {
+        this.currentRow = { ...row }
+        this.isEditMode = false
+        this.detailDialogTitle = '详情'
+        this.detailDialogVisible = true
+      },
+      // 编辑
+      handleEdit(row) {
+        this.currentRow = { ...row }
+        this.isEditMode = true
+        this.detailDialogTitle = '编辑'
+        this.detailDialogVisible = true
+      },
+      // 保存详情
+      handleSaveDetail() {
+        // 验证表格数据
+        if (this.$refs.fixedAssetsTable) {
+          const isValid = this.$refs.fixedAssetsTable.validate()
+          if (!isValid) {
+            const errors = this.$refs.fixedAssetsTable.validationErrors
+            Message.error('数据验证失败:\n' + errors.join('\n'))
+            return
+          }
+
+          // 获取表格数据
+          const tableData = this.$refs.fixedAssetsTable.getTableData()
+          if (this.currentRow) {
+            // 更新当前行的数据
+            this.currentRow.data = tableData
+            this.currentRow.lastModifyTime = this.formatDateTime(new Date())
+
+            // 更新本地表格数据
+            const index = this.localTableData.findIndex(
+              (item) => item.id === this.currentRow.id
+            )
+            if (index > -1) {
+              this.$set(this.localTableData, index, { ...this.currentRow })
+            }
+
+            Message.success('保存成功')
+            this.detailDialogVisible = false
+          }
+        }
+      },
+      // 删除单条记录
+      handleDelete(row) {
+        MessageBox.confirm('确定要删除这条记录吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        })
+          .then(() => {
+            const index = this.localTableData.findIndex(
+              (item) => item.id === row.id
+            )
+            if (index > -1) {
+              this.localTableData.splice(index, 1)
+              this.pagination.total = this.localTableData.length
+
+              // 如果当前页没有数据了,跳转到上一页
+              if (
+                this.paginatedTableData.length === 0 &&
+                this.pagination.currentPage > 1
+              ) {
+                this.pagination.currentPage--
+              }
+
+              Message.success('删除成功')
+            }
+          })
+          .catch(() => {})
+      },
+      // 详情/编辑保存
+      handleDetailSave(saveData) {
+        if (this.currentRow) {
+          // 更新当前行的数据
+          this.currentRow.data = saveData
+          this.currentRow.lastModifyTime = this.formatDateTime(new Date())
+
+          // 更新本地表格数据
+          const index = this.localTableData.findIndex(
+            (item) => item.id === this.currentRow.id
+          )
+          if (index > -1) {
+            this.$set(this.localTableData, index, { ...this.currentRow })
+          }
+
+          Message.success('保存成功')
+          this.detailDialogVisible = false
+        }
+      },
+      // 格式化日期时间
+      formatDateTime(date) {
+        const year = date.getFullYear()
+        const month = String(date.getMonth() + 1).padStart(2, '0')
+        const day = String(date.getDate()).padStart(2, '0')
+        const hours = String(date.getHours()).padStart(2, '0')
+        const minutes = String(date.getMinutes()).padStart(2, '0')
+        const seconds = String(date.getSeconds()).padStart(2, '0')
+        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+      },
+      // 分页变化
+      handlePageChange(page) {
+        this.pagination.currentPage = page
+      },
+      // 每页条数变化
+      handleSizeChange(size) {
+        this.pagination.pageSize = size
+        this.pagination.currentPage = 1
+      },
+      // 关闭弹窗
+      handleClose() {
+        this.dialogVisible = false
+        this.$emit('update:visible', false)
+      },
+      // 取消
+      handleCancel() {
+        this.handleClose()
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss">
+  .action-buttons {
+    margin-bottom: 20px;
+
+    .el-button {
+      margin-right: 10px;
+    }
+  }
+
+  .dialog-footer {
+    text-align: center;
+    margin-top: 20px;
+    .el-button {
+      margin: 0 10px;
+    }
+  }
+
+  ::v-deep .el-dialog__header {
+    padding: 20px 20px 10px;
+    .el-dialog__title {
+      font-size: 18px;
+      font-weight: 600;
+      color: #303133;
+    }
+  }
+
+  // 操作按钮样式
+  ::v-deep .el-table {
+    .el-button--text {
+      padding: 0 5px;
+    }
+  }
+</style>

+ 858 - 0
src/views/EntDeclaration/auditTaskManagement/components/FixedAssetsTable.vue

@@ -0,0 +1,858 @@
+<template>
+  <div class="fixed-assets-table-container">
+    <el-table
+      :data="flattenedTableData"
+      border
+      style="width: 100%"
+      size="small"
+      :row-class-name="getRowClassName"
+    >
+      <!-- 序号列 -->
+      <el-table-column prop="seq" label="序号" width="80" align="center">
+        <template slot-scope="scope">
+          <span v-if="scope.row.isCategory" class="category-seq">
+            {{ scope.row.categorySeq }}
+          </span>
+          <span v-else>{{ scope.row.seq }}</span>
+        </template>
+      </el-table-column>
+
+      <!-- 项目列 -->
+      <el-table-column
+        prop="itemName"
+        label="项目"
+        min-width="200"
+        align="left"
+      >
+        <template slot-scope="scope">
+          <span v-if="scope.row.isCategory" class="category-name">
+            {{ scope.row.itemName }}
+          </span>
+          <el-input
+            v-else
+            v-model="scope.row.itemName"
+            placeholder="请输入项目名称"
+            size="mini"
+            :disabled="isViewMode"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 计量单位列 -->
+      <el-table-column prop="unit" label="计量单位" width="120" align="center">
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.unit"
+            placeholder="单位"
+            size="mini"
+            :disabled="isViewMode"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 固定资产原值列 -->
+      <el-table-column
+        prop="originalValue"
+        label="固定资产原值"
+        width="150"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.originalValue"
+            placeholder="原值"
+            size="mini"
+            :disabled="isViewMode"
+            @blur="handleCellBlur(scope.row, 'originalValue')"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 入帐或竣工验收日期列 -->
+      <el-table-column
+        prop="entryDate"
+        label="入帐或竣工验收日期"
+        width="180"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-date-picker
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.entryDate"
+            type="date"
+            placeholder="选择日期"
+            size="mini"
+            format="yyyy-MM-dd"
+            value-format="yyyy-MM-dd"
+            :disabled="isViewMode"
+            style="width: 100%"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 折旧年限列 -->
+      <el-table-column
+        prop="depreciationPeriod"
+        label="折旧年限"
+        width="120"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.depreciationPeriod"
+            placeholder="年限"
+            size="mini"
+            :disabled="isViewMode"
+            @blur="handleCellBlur(scope.row, 'depreciationPeriod')"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 折旧费列 -->
+      <el-table-column
+        prop="depreciationExpense"
+        label="折旧费"
+        width="120"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.depreciationExpense"
+            placeholder="费用"
+            size="mini"
+            :disabled="isViewMode"
+            @blur="handleCellBlur(scope.row, 'depreciationExpense')"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 资金来源列 -->
+      <el-table-column
+        prop="fundSource"
+        label="资金来源"
+        width="120"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.fundSource"
+            placeholder="来源"
+            size="mini"
+            :disabled="isViewMode"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 备注列 -->
+      <el-table-column prop="remark" label="备注" min-width="150">
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.remark"
+            placeholder="备注"
+            size="mini"
+            :disabled="isViewMode"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 操作列 -->
+      <el-table-column label="操作" width="100" align="center" fixed="right">
+        <template slot-scope="scope">
+          <div v-if="scope.row.isCategory" class="operation-buttons">
+            <el-button
+              type="text"
+              size="mini"
+              icon="el-icon-plus"
+              :disabled="isViewMode"
+              @click="handleAddRow(scope.row)"
+            />
+            <el-button
+              type="text"
+              size="mini"
+              icon="el-icon-minus"
+              :disabled="isViewMode"
+              @click="handleDeleteRow(scope.row)"
+            />
+          </div>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+
+<script>
+  import { Message } from 'element-ui'
+
+  export default {
+    name: 'FixedAssetsTable',
+    props: {
+      // 表格数据配置(嵌套结构)
+      tableItems: {
+        type: Array,
+        default: () => [],
+      },
+      // 是否有保存的数据
+      savedData: {
+        type: Object,
+        default: () => ({}),
+      },
+      // 是否查看模式
+      isViewMode: {
+        type: Boolean,
+        default: false,
+      },
+    },
+    data() {
+      return {
+        // 嵌套的表格数据
+        fixedAssetsData: [],
+        // 验证错误
+        validationErrors: [],
+        // 扁平化的表格数据(响应式)
+        flattenedData: [],
+      }
+    },
+    computed: {
+      // 扁平化的表格数据(从嵌套结构生成)
+      flattenedTableData() {
+        return this.flattenedData
+      },
+    },
+    watch: {
+      tableItems: {
+        handler(newVal) {
+          if (newVal && newVal.length > 0) {
+            this.fixedAssetsData = this.deepClone(newVal)
+          } else {
+            this.fixedAssetsData = this.getDefaultTableData()
+          }
+          // 重新生成扁平数据
+          this.generateFlattenedData()
+        },
+        immediate: true,
+        deep: true,
+      },
+      savedData: {
+        handler() {
+          // 数据变化时重新生成扁平数据
+          this.generateFlattenedData()
+        },
+        deep: true,
+      },
+    },
+    methods: {
+      // 生成扁平数据
+      generateFlattenedData() {
+        const result = []
+        let seq = 1
+
+        const processItem = (item, parentCategory = null) => {
+          if (item.isCategory) {
+            // 分类行
+            result.push({
+              ...item,
+              seq: item.categorySeq || item.id,
+              isCategory: true,
+              categorySeq: item.categorySeq || item.id,
+            })
+
+            // 处理分类下的子项
+            if (item.children && Array.isArray(item.children)) {
+              item.children.forEach((child) => {
+                processItem(child, item)
+              })
+            }
+          } else {
+            // 普通行
+            const rowData = {
+              ...item,
+              seq: seq++,
+              isCategory: false,
+            }
+
+            // 如果有父分类,设置分类信息
+            if (parentCategory) {
+              rowData.categoryId = parentCategory.id
+              rowData.categorySeq =
+                parentCategory.categorySeq || parentCategory.id
+            }
+
+            // 初始化字段
+            if (rowData.itemName === undefined) rowData.itemName = ''
+            if (rowData.unit === undefined) rowData.unit = ''
+            if (rowData.originalValue === undefined) rowData.originalValue = ''
+            if (rowData.entryDate === undefined) rowData.entryDate = ''
+            if (rowData.depreciationPeriod === undefined)
+              rowData.depreciationPeriod = ''
+            if (rowData.depreciationExpense === undefined)
+              rowData.depreciationExpense = ''
+            if (rowData.fundSource === undefined) rowData.fundSource = ''
+            if (rowData.remark === undefined) rowData.remark = ''
+
+            // 如果有保存的数据,填充值
+            if (this.savedData) {
+              // 从保存的数据中查找对应的值
+              const savedItem = this.findSavedItemById(item.id)
+              if (savedItem) {
+                Object.keys(savedItem).forEach((key) => {
+                  if (savedItem[key] !== undefined && key !== 'id') {
+                    rowData[key] = savedItem[key]
+                  }
+                })
+              }
+            }
+
+            result.push(rowData)
+
+            // 如果有子项,递归处理
+            if (item.children && Array.isArray(item.children)) {
+              item.children.forEach((child) => {
+                processItem(child, item)
+              })
+            }
+          }
+        }
+
+        // 处理所有项
+        this.fixedAssetsData.forEach((item) => {
+          processItem(item)
+        })
+
+        // 使用 Vue.set 确保响应式
+        this.$set(this, 'flattenedData', result)
+      },
+      // 深拷贝
+      deepClone(obj) {
+        if (obj === null || typeof obj !== 'object') return obj
+        if (obj instanceof Date) return new Date(obj.getTime())
+        if (obj instanceof Array) return obj.map((item) => this.deepClone(item))
+        if (typeof obj === 'object') {
+          const clonedObj = {}
+          for (const key in obj) {
+            if (obj.hasOwnProperty(key)) {
+              clonedObj[key] = this.deepClone(obj[key])
+            }
+          }
+          return clonedObj
+        }
+      },
+      // 获取默认表格数据
+      getDefaultTableData() {
+        return [
+          {
+            id: 'I',
+            itemName: '房屋建筑物',
+            isCategory: true,
+            categorySeq: 'I',
+            children: [
+              {
+                id: 'I-1',
+                itemName: '办公用房',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'I-2',
+                itemName: '教保用房',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'I-3',
+                itemName: '幼儿宿舍用房',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'I-4',
+                itemName: '其它',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'II',
+            itemName: '交通运输工具',
+            isCategory: true,
+            categorySeq: 'II',
+            children: [
+              {
+                id: 'II-1',
+                itemName: '车辆',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'III',
+            itemName: '教保专用设备',
+            isCategory: true,
+            categorySeq: 'III',
+            children: [
+              {
+                id: 'III-1',
+                itemName: '电教',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'III-2',
+                itemName: '文体',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'IV',
+            itemName: '办公设备',
+            isCategory: true,
+            categorySeq: 'IV',
+            children: [
+              {
+                id: 'IV-1',
+                itemName: '电脑',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+          {
+            id: 'V',
+            itemName: '其它固定资产',
+            isCategory: true,
+            categorySeq: 'V',
+            children: [
+              {
+                id: 'V-1',
+                itemName: '空调',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-2',
+                itemName: '家电',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-3',
+                itemName: '供水系统',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-4',
+                itemName: '洗涤用具',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-5',
+                itemName: '家具',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-6',
+                itemName: '炊事用具',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+              {
+                id: 'V-7',
+                itemName: '其它',
+                unit: '',
+                originalValue: '',
+                entryDate: '',
+                depreciationPeriod: '',
+                depreciationExpense: '',
+                fundSource: '',
+                remark: '',
+              },
+            ],
+          },
+        ]
+      },
+      // 获取行样式类名
+      getRowClassName({ row }) {
+        if (row.isCategory) {
+          return 'category-row'
+        }
+        return ''
+      },
+      // 添加行
+      handleAddRow(row) {
+        // 找到对应的分类
+        const category = this.findCategoryById(row.id)
+        if (category) {
+          // 生成新的项目ID
+          const newId = `${row.id}-${Date.now()}`
+          const newItem = {
+            id: newId,
+            itemName: '',
+            unit: '',
+            originalValue: '',
+            entryDate: '',
+            depreciationPeriod: '',
+            depreciationExpense: '',
+            fundSource: '',
+            remark: '',
+          }
+
+          // 在分类的 children 数组末尾添加新行
+          if (!category.children) {
+            this.$set(category, 'children', [])
+          }
+          category.children.push(newItem)
+
+          // 重新生成扁平数据
+          this.generateFlattenedData()
+          Message.success('添加行成功')
+        }
+      },
+      // 删除行(删除分类下的最后一个子项)
+      handleDeleteRow(row) {
+        // row 是分类行,需要找到该分类下的子项
+        const category = this.findCategoryById(row.id)
+        if (category && category.children && category.children.length > 0) {
+          // 删除最后一个子项
+          category.children.pop()
+          // 重新生成扁平数据
+          this.generateFlattenedData()
+          Message.success('删除成功')
+        } else {
+          Message.warning('该分类下没有可删除的行')
+        }
+      },
+      // 根据ID在保存的数据中查找
+      findSavedItemById(id) {
+        if (!this.savedData) return null
+
+        // 递归查找
+        const findInArray = (items) => {
+          for (const item of items) {
+            if (item.id === id) {
+              return item
+            }
+            if (item.children && Array.isArray(item.children)) {
+              const found = findInArray(item.children)
+              if (found) return found
+            }
+          }
+          return null
+        }
+
+        // 如果 savedData 是数组
+        if (Array.isArray(this.savedData)) {
+          return findInArray(this.savedData)
+        }
+
+        // 如果 savedData 是对象,尝试查找
+        if (typeof this.savedData === 'object') {
+          // 可能是一个映射对象,key 是 id
+          if (this.savedData[id]) {
+            return this.savedData[id]
+          }
+          // 或者是嵌套结构
+          return findInArray([this.savedData])
+        }
+
+        return null
+      },
+      // 根据ID查找分类
+      findCategoryById(id) {
+        const findInArray = (items) => {
+          for (const item of items) {
+            if (item.id === id) {
+              return item
+            }
+            if (item.children && Array.isArray(item.children)) {
+              const found = findInArray(item.children)
+              if (found) return found
+            }
+          }
+          return null
+        }
+        return findInArray(this.fixedAssetsData)
+      },
+      // 单元格失焦验证
+      handleCellBlur(row, field) {
+        // 实时验证格式
+        if (field === 'originalValue' || field === 'depreciationExpense') {
+          const value = row[field]
+          if (value && !/^\d+(\.\d+)?$/.test(value)) {
+            Message.warning(
+              `${this.getFieldLabel(field)}格式不正确,请输入数字`
+            )
+          }
+        }
+        if (field === 'depreciationPeriod') {
+          const value = row[field]
+          if (value && !/^\d+$/.test(value)) {
+            Message.warning(`${this.getFieldLabel(field)}必须是正整数`)
+          }
+        }
+      },
+      // 获取字段标签
+      getFieldLabel(field) {
+        const labels = {
+          originalValue: '固定资产原值',
+          depreciationPeriod: '折旧年限',
+          depreciationExpense: '折旧费',
+        }
+        return labels[field] || field
+      },
+      // 验证表单
+      validate() {
+        this.validationErrors = []
+        const errors = []
+
+        // 验证扁平数据(因为用户编辑的是扁平数据)
+        const flatData = this.flattenedTableData
+        flatData.forEach((item, index) => {
+          if (!item.isCategory) {
+            // 非空验证
+            if (!item.itemName || String(item.itemName).trim() === '') {
+              errors.push(`第${item.seq}行:项目名称不能为空`)
+            }
+            if (!item.unit || String(item.unit).trim() === '') {
+              errors.push(`第${item.seq}行:计量单位不能为空`)
+            }
+            if (
+              !item.originalValue ||
+              String(item.originalValue).trim() === ''
+            ) {
+              errors.push(`第${item.seq}行:固定资产原值不能为空`)
+            }
+            if (!item.entryDate || String(item.entryDate).trim() === '') {
+              errors.push(`第${item.seq}行:入帐或竣工验收日期不能为空`)
+            }
+            if (
+              !item.depreciationPeriod ||
+              String(item.depreciationPeriod).trim() === ''
+            ) {
+              errors.push(`第${item.seq}行:折旧年限不能为空`)
+            }
+            if (
+              !item.depreciationExpense ||
+              String(item.depreciationExpense).trim() === ''
+            ) {
+              errors.push(`第${item.seq}行:折旧费不能为空`)
+            }
+            if (!item.fundSource || String(item.fundSource).trim() === '') {
+              errors.push(`第${item.seq}行:资金来源不能为空`)
+            }
+
+            // 格式验证
+            if (
+              item.originalValue &&
+              String(item.originalValue).trim() !== '' &&
+              !/^\d+(\.\d+)?$/.test(String(item.originalValue))
+            ) {
+              errors.push(`第${item.seq}行:固定资产原值格式不正确,请输入数字`)
+            }
+            if (
+              item.depreciationPeriod &&
+              String(item.depreciationPeriod).trim() !== '' &&
+              !/^\d+$/.test(String(item.depreciationPeriod))
+            ) {
+              errors.push(`第${item.seq}行:折旧年限必须是正整数`)
+            }
+            if (
+              item.depreciationExpense &&
+              String(item.depreciationExpense).trim() !== '' &&
+              !/^\d+(\.\d+)?$/.test(String(item.depreciationExpense))
+            ) {
+              errors.push(`第${item.seq}行:折旧费格式不正确,请输入数字`)
+            }
+          }
+        })
+
+        this.validationErrors = errors
+        return errors.length === 0
+      },
+      // 获取表格数据(用于保存)
+      // 需要将扁平数据同步回嵌套结构
+      getTableData() {
+        // 同步扁平数据的修改到嵌套结构
+        const flatData = this.flattenedData
+        const syncDataToNested = (items) => {
+          return items.map((item) => {
+            if (item.isCategory) {
+              // 分类行
+              const newItem = { ...item }
+              if (item.children && Array.isArray(item.children)) {
+                newItem.children = syncDataToNested(item.children)
+              }
+              return newItem
+            } else {
+              // 普通行,从扁平数据中同步
+              const flatItem = flatData.find(
+                (f) => f.id === item.id && !f.isCategory
+              )
+              if (flatItem) {
+                return {
+                  ...item,
+                  itemName: flatItem.itemName,
+                  unit: flatItem.unit,
+                  originalValue: flatItem.originalValue,
+                  entryDate: flatItem.entryDate,
+                  depreciationPeriod: flatItem.depreciationPeriod,
+                  depreciationExpense: flatItem.depreciationExpense,
+                  fundSource: flatItem.fundSource,
+                  remark: flatItem.remark,
+                }
+              }
+              return item
+            }
+          })
+        }
+
+        return syncDataToNested(this.fixedAssetsData)
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss">
+  .fixed-assets-table-container {
+    // 分类行样式
+    ::v-deep .category-row {
+      background-color: #f5f7fa !important;
+
+      td {
+        background-color: #f5f7fa !important;
+        font-weight: bold;
+      }
+
+      .category-name {
+        color: #409eff;
+        font-weight: bold;
+      }
+
+      .category-seq {
+        color: #409eff;
+        font-weight: bold;
+      }
+    }
+
+    // 操作按钮样式
+    .operation-buttons {
+      display: flex;
+      justify-content: center;
+      gap: 5px;
+
+      .el-button {
+        padding: 5px;
+        min-width: 24px;
+        height: 24px;
+        border-radius: 50%;
+        background-color: #000;
+        color: #fff;
+        border: none;
+
+        &:hover {
+          background-color: #333;
+        }
+
+        i {
+          font-size: 14px;
+        }
+      }
+    }
+
+    // 输入框样式
+    ::v-deep .el-input__inner {
+      border: 1px solid #dcdfe6;
+      border-radius: 4px;
+
+      &:focus {
+        border-color: #409eff;
+      }
+    }
+
+    // 日期选择器样式
+    ::v-deep .el-date-editor {
+      width: 100%;
+    }
+  }
+</style>

+ 690 - 0
src/views/EntDeclaration/auditTaskManagement/components/FixedTableDialog.vue

@@ -0,0 +1,690 @@
+<template>
+  <el-dialog
+    title="调查表填报"
+    :visible.sync="dialogVisible"
+    width="90%"
+    :close-on-click-modal="false"
+    :show-close="true"
+    append-to-body
+    :modal="false"
+    @close="handleClose"
+  >
+    <el-table
+      :data="tableData"
+      border
+      style="width: 100%"
+      :row-class-name="getRowClassName"
+    >
+      <!-- 序号列 -->
+      <el-table-column prop="seq" label="序号" width="80" align="center">
+        <template slot-scope="scope">
+          <span v-if="scope.row.isCategory" class="category-seq">
+            {{ scope.row.categorySeq }}
+          </span>
+          <span v-else>{{ scope.row.seq }}</span>
+        </template>
+      </el-table-column>
+
+      <!-- 项目列(只读) -->
+      <el-table-column
+        prop="itemName"
+        label="项目"
+        min-width="200"
+        align="left"
+      >
+        <template slot-scope="scope">
+          <span v-if="scope.row.isCategory" class="category-name">
+            {{ scope.row.itemName }}
+          </span>
+          <span v-else>{{ scope.row.itemName }}</span>
+        </template>
+      </el-table-column>
+
+      <!-- 单位列(只读) -->
+      <el-table-column prop="unit" label="单位" width="100" align="center">
+        <template slot-scope="scope">
+          <span v-if="!scope.row.isCategory">{{ scope.row.unit }}</span>
+        </template>
+      </el-table-column>
+
+      <!-- 动态年份列 -->
+      <el-table-column
+        v-for="year in yearColumns"
+        :key="year"
+        :label="`${year}年`"
+        :prop="`year_${year}`"
+        width="150"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row[`year_${year}`]"
+            :placeholder="`请输入${year}年数据`"
+            :disabled="isViewMode"
+            @blur="handleCellBlur(scope.row, year)"
+            @input="handleCellInput(scope.row, year)"
+          />
+        </template>
+      </el-table-column>
+
+      <!-- 备注列 -->
+      <el-table-column prop="remark" label="备注" min-width="150" align="left">
+        <template slot-scope="scope">
+          <el-input
+            v-if="!scope.row.isCategory"
+            v-model="scope.row.remark"
+            placeholder="请输入备注"
+            :disabled="isViewMode"
+          />
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <div slot="footer" class="dialog-footer">
+      <el-button type="primary" @click="handleSave">保存</el-button>
+      <el-button @click="handleCancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  import { Message } from 'element-ui'
+
+  export default {
+    name: 'FixedTableDialog',
+    props: {
+      visible: {
+        type: Boolean,
+        default: false,
+      },
+      surveyData: {
+        type: Object,
+        default: () => ({}),
+      },
+      // 表格数据配置
+      // 格式: [
+      //   {
+      //     id: '1',
+      //     itemName: '班级数',
+      //     unit: '个',
+      //     isCategory: false,
+      //     parentId: null,
+      //     categoryId: 'III',
+      //     seq: 1,
+      //     validateRules: {
+      //       required: true,
+      //       type: 'number',
+      //       min: 0,
+      //     },
+      //     linkageRules: {
+      //       parent: 'III',
+      //       relation: 'sum',
+      //     },
+      //   },
+      //   {
+      //     id: 'III',
+      //     itemName: '在取做保职工总人数',
+      //     unit: '人',
+      //     isCategory: true,
+      //     categorySeq: 'III',
+      //     children: [...],
+      //   }
+      // ]
+      tableItems: {
+        type: Array,
+        default: () => [],
+      },
+      // 监审期间(年份数组)
+      // 格式: ['2022', '2023', '2024']
+      auditPeriods: {
+        type: Array,
+        default: () => [],
+      },
+      // 是否查看模式
+      isViewMode: {
+        type: Boolean,
+        default: false,
+      },
+    },
+    data() {
+      return {
+        dialogVisible: false,
+        tableData: [],
+        yearColumns: [],
+        validationErrors: [],
+      }
+    },
+    watch: {
+      visible: {
+        handler(newVal) {
+          this.dialogVisible = newVal
+          if (newVal) {
+            this.initTableData()
+          }
+        },
+        immediate: true,
+      },
+      dialogVisible(newVal) {
+        if (!newVal) {
+          this.$emit('update:visible', false)
+        }
+      },
+      tableItems: {
+        handler() {
+          if (this.dialogVisible) {
+            this.initTableData()
+          }
+        },
+        deep: true,
+      },
+      auditPeriods: {
+        handler() {
+          if (this.dialogVisible) {
+            this.initYearColumns()
+            this.initTableData()
+          }
+        },
+        deep: true,
+      },
+    },
+    mounted() {
+      this.initYearColumns()
+    },
+    methods: {
+      // 初始化年份列
+      initYearColumns() {
+        if (this.auditPeriods && this.auditPeriods.length > 0) {
+          // 如果传入了监审期间,使用监审期间
+          this.yearColumns = this.auditPeriods.map((period) => {
+            // 如果是日期格式,提取年份
+            if (typeof period === 'string' && period.includes('-')) {
+              return period.split('-')[0]
+            }
+            return String(period)
+          })
+        } else if (this.surveyData && this.surveyData.auditPeriod) {
+          // 如果从 surveyData 中获取监审期间
+          const periods = this.parseAuditPeriod(this.surveyData.auditPeriod)
+          this.yearColumns = periods
+        } else {
+          // 默认使用最近3年
+          const currentYear = new Date().getFullYear()
+          this.yearColumns = [
+            String(currentYear - 2),
+            String(currentYear - 1),
+            String(currentYear),
+          ]
+        }
+      },
+      // 解析监审期间字符串(如 "2022,2023,2024" 或 "2022-2024")
+      parseAuditPeriod(periodStr) {
+        if (!periodStr) return []
+        if (periodStr.includes(',')) {
+          return periodStr.split(',').map((p) => p.trim())
+        }
+        if (periodStr.includes('-')) {
+          const parts = periodStr.split('-')
+          if (parts.length === 2) {
+            const start = parseInt(parts[0].trim())
+            const end = parseInt(parts[1].trim())
+            const years = []
+            for (let year = start; year <= end; year++) {
+              years.push(String(year))
+            }
+            return years
+          }
+        }
+        return [String(periodStr)]
+      },
+      // 初始化表格数据
+      initTableData() {
+        if (!this.tableItems || this.tableItems.length === 0) {
+          // 如果没有传入数据,使用假数据
+          this.tableData = this.getMockTableData()
+          return
+        }
+
+        // 将嵌套结构转换为扁平结构(递归处理)
+        const flatData = []
+        let seq = 1
+
+        const processItem = (item, parentCategory = null) => {
+          if (item.isCategory) {
+            // 分类行
+            const categoryRow = {
+              ...item,
+              seq: item.categorySeq || item.id,
+              isCategory: true,
+              categorySeq: item.categorySeq || item.id,
+            }
+
+            // 初始化年份数据(分类行也可以有数据)
+            this.yearColumns.forEach((year) => {
+              categoryRow[`year_${year}`] = item[`year_${year}`] || ''
+            })
+
+            // 如果有传入的数据,填充值
+            if (this.surveyData && this.surveyData[item.id]) {
+              const savedData = this.surveyData[item.id]
+              this.yearColumns.forEach((year) => {
+                if (savedData[year] !== undefined) {
+                  categoryRow[`year_${year}`] = savedData[year]
+                }
+              })
+            }
+
+            flatData.push(categoryRow)
+
+            // 处理分类下的子项
+            if (item.children && Array.isArray(item.children)) {
+              item.children.forEach((child) => {
+                processItem(child, item)
+              })
+            }
+          } else {
+            // 普通行
+            const rowData = {
+              ...item,
+              seq: seq++,
+              isCategory: false,
+            }
+
+            // 如果有父分类,设置分类信息
+            if (parentCategory) {
+              rowData.categoryId = parentCategory.id
+              rowData.categorySeq =
+                parentCategory.categorySeq || parentCategory.id
+            }
+
+            // 初始化年份数据
+            this.yearColumns.forEach((year) => {
+              rowData[`year_${year}`] = item[`year_${year}`] || ''
+            })
+
+            // 初始化备注
+            rowData.remark = item.remark || ''
+
+            // 如果有传入的数据,填充值
+            if (this.surveyData && this.surveyData[item.id]) {
+              const savedData = this.surveyData[item.id]
+              this.yearColumns.forEach((year) => {
+                if (savedData[year] !== undefined) {
+                  rowData[`year_${year}`] = savedData[year]
+                }
+              })
+              if (savedData.remark !== undefined) {
+                rowData.remark = savedData.remark
+              }
+            }
+
+            flatData.push(rowData)
+
+            // 如果有子项,递归处理
+            if (item.children && Array.isArray(item.children)) {
+              item.children.forEach((child) => {
+                processItem(child, item)
+              })
+            }
+          }
+        }
+
+        // 处理所有项
+        this.tableItems.forEach((item) => {
+          processItem(item)
+        })
+
+        this.tableData = flatData
+      },
+      // 获取假数据(用于测试)
+      getMockTableData() {
+        return [
+          {
+            id: '1',
+            itemName: '班级数',
+            unit: '个',
+            isCategory: false,
+            seq: 1,
+            year_2022: '',
+            year_2023: '',
+            year_2024: '',
+            remark: '',
+          },
+          {
+            id: '2',
+            itemName: '幼儿学生人数',
+            unit: '人',
+            isCategory: false,
+            seq: 2,
+            year_2022: '',
+            year_2023: '',
+            year_2024: '',
+            remark: '',
+          },
+          {
+            id: 'III',
+            itemName: '在取做保职工总人数',
+            unit: '人',
+            isCategory: true,
+            categorySeq: 'III',
+            seq: 'III',
+          },
+          {
+            id: '3-1',
+            itemName: '行政管理人员数',
+            unit: '人',
+            isCategory: false,
+            categoryId: 'III',
+            categorySeq: 'III',
+            seq: 3,
+            year_2022: '',
+            year_2023: '',
+            year_2024: '',
+            remark: '',
+          },
+          {
+            id: '3-2',
+            itemName: '教师人数',
+            unit: '人',
+            isCategory: false,
+            categoryId: 'III',
+            categorySeq: 'III',
+            seq: 4,
+            year_2022: '',
+            year_2023: '',
+            year_2024: '',
+            remark: '',
+          },
+          {
+            id: '3-3',
+            itemName: '保育员人数',
+            unit: '人',
+            isCategory: false,
+            categoryId: 'III',
+            categorySeq: 'III',
+            seq: 5,
+            year_2022: '',
+            year_2023: '',
+            year_2024: '',
+            remark: '',
+          },
+        ]
+      },
+      // 获取行样式类名
+      getRowClassName({ row }) {
+        if (row.isCategory) {
+          return 'category-row'
+        }
+        return ''
+      },
+      // 单元格输入事件
+      handleCellInput(row, year) {
+        // 实时验证勾稽关系
+        this.validateLinkage(row, year)
+      },
+      // 单元格失焦事件
+      handleCellBlur(row, year) {
+        // 验证格式和非空
+        this.validateCell(row, year)
+        // 验证勾稽关系
+        this.validateLinkage(row, year)
+      },
+      // 验证单元格(非空和格式验证)
+      validateCell(row, year) {
+        const fieldName = `year_${year}`
+        const value = row[fieldName]
+
+        // 非空验证
+        if (row.validateRules && row.validateRules.required && !value) {
+          this.showFieldError(
+            row,
+            year,
+            `${row.itemName}的${year}年数据不能为空`
+          )
+          return false
+        }
+
+        // 格式验证
+        if (value && row.validateRules) {
+          if (row.validateRules.type === 'number') {
+            const numValue = Number(value)
+            if (isNaN(numValue)) {
+              this.showFieldError(
+                row,
+                year,
+                `${row.itemName}的${year}年数据必须是数字`
+              )
+              return false
+            }
+            if (
+              row.validateRules.min !== undefined &&
+              numValue < row.validateRules.min
+            ) {
+              this.showFieldError(
+                row,
+                year,
+                `${row.itemName}的${year}年数据不能小于${row.validateRules.min}`
+              )
+              return false
+            }
+            if (
+              row.validateRules.max !== undefined &&
+              numValue > row.validateRules.max
+            ) {
+              this.showFieldError(
+                row,
+                year,
+                `${row.itemName}的${year}年数据不能大于${row.validateRules.max}`
+              )
+              return false
+            }
+          }
+        }
+
+        return true
+      },
+      // 验证勾稽关系
+      validateLinkage(row, year) {
+        if (!row.linkageRules) return true
+
+        const { parent, relation } = row.linkageRules
+
+        if (relation === 'sum') {
+          // 验证子项之和等于父项
+          const parentRow = this.tableData.find((r) => r.id === parent)
+          if (!parentRow || parentRow.isCategory) return true
+
+          const children = this.tableData.filter(
+            (r) => r.categoryId === parent && !r.isCategory
+          )
+
+          const parentValue = Number(parentRow[`year_${year}`]) || 0
+          const sumValue = children.reduce((sum, child) => {
+            return sum + (Number(child[`year_${year}`]) || 0)
+          }, 0)
+
+          if (parentValue !== sumValue) {
+            // 可以选择自动修正或提示错误
+            // 这里仅提示,不自动修正
+            console.warn(
+              `${parentRow.itemName}的${year}年数据(${parentValue})与子项之和(${sumValue})不相等`
+            )
+          }
+        }
+
+        return true
+      },
+      // 显示字段错误
+      showFieldError(row, year, message) {
+        // 这里可以添加更详细的错误提示
+        console.error(message)
+      },
+      // 保存前验证
+      validateBeforeSave() {
+        this.validationErrors = []
+        let isValid = true
+
+        // 验证所有单元格
+        this.tableData.forEach((row) => {
+          if (row.isCategory) return
+
+          this.yearColumns.forEach((year) => {
+            const cellValid = this.validateCell(row, year)
+            if (!cellValid) {
+              isValid = false
+              this.validationErrors.push({
+                row: row.itemName,
+                year,
+                message: `${row.itemName}的${year}年数据验证失败`,
+              })
+            }
+          })
+
+          // 验证勾稽关系
+          this.yearColumns.forEach((year) => {
+            const linkageValid = this.validateLinkage(row, year)
+            if (!linkageValid) {
+              isValid = false
+            }
+          })
+        })
+
+        // 验证所有勾稽关系
+        this.validateAllLinkages()
+
+        return isValid
+      },
+      // 验证所有勾稽关系
+      validateAllLinkages() {
+        const categories = this.tableData.filter((r) => r.isCategory)
+
+        categories.forEach((category) => {
+          const children = this.tableData.filter(
+            (r) => r.categoryId === category.id && !r.isCategory
+          )
+
+          this.yearColumns.forEach((year) => {
+            const categoryValue = Number(category[`year_${year}`]) || 0
+            const sumValue = children.reduce((sum, child) => {
+              return sum + (Number(child[`year_${year}`]) || 0)
+            }, 0)
+
+            if (categoryValue !== 0 && categoryValue !== sumValue) {
+              this.validationErrors.push({
+                row: category.itemName,
+                year,
+                message: `${category.itemName}的${year}年数据(${categoryValue})与子项之和(${sumValue})不相等`,
+              })
+            }
+          })
+        })
+      },
+      // 关闭弹窗
+      handleClose() {
+        this.dialogVisible = false
+        this.$emit('update:visible', false)
+      },
+      // 取消
+      handleCancel() {
+        this.handleClose()
+      },
+      // 保存
+      handleSave() {
+        // 验证数据
+        if (!this.validateBeforeSave()) {
+          const errorMessages = this.validationErrors
+            .map((err) => `${err.row}的${err.year}年:${err.message}`)
+            .join('\n')
+          Message.error('数据验证失败:\n' + errorMessages)
+          return
+        }
+
+        // 格式化保存数据
+        const saveData = {
+          items: this.tableData.map((row) => {
+            const itemData = {
+              id: row.id,
+              itemName: row.itemName,
+            }
+
+            // 添加年份数据
+            this.yearColumns.forEach((year) => {
+              if (!row.isCategory) {
+                itemData[year] = row[`year_${year}`] || ''
+              }
+            })
+
+            // 添加备注
+            if (!row.isCategory) {
+              itemData.remark = row.remark || ''
+            }
+
+            return itemData
+          }),
+          yearColumns: this.yearColumns,
+        }
+
+        console.log('保存数据:', saveData)
+        Message.success('保存成功')
+
+        // 触发保存事件
+        this.$emit('save', saveData)
+        this.handleClose()
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss">
+  .dialog-footer {
+    text-align: center;
+    margin-top: 20px;
+    .el-button {
+      margin: 0 10px;
+    }
+  }
+
+  ::v-deep .el-dialog__header {
+    padding: 20px 20px 10px;
+    .el-dialog__title {
+      font-size: 18px;
+      font-weight: 600;
+      color: #303133;
+    }
+  }
+
+  // 分类行样式
+  ::v-deep .category-row {
+    background-color: #f5f7fa !important;
+
+    td {
+      background-color: #f5f7fa !important;
+      font-weight: bold;
+    }
+
+    .category-name {
+      color: #409eff;
+      font-weight: bold;
+    }
+
+    .category-seq {
+      color: #409eff;
+      font-weight: bold;
+    }
+  }
+
+  // 表格输入框样式
+  ::v-deep .el-table {
+    .el-input {
+      .el-input__inner {
+        border: none;
+        padding: 0 5px;
+        text-align: center;
+
+        &:focus {
+          border: 1px solid #409eff;
+        }
+      }
+    }
+  }
+</style>

+ 436 - 0
src/views/EntDeclaration/auditTaskManagement/components/SurveyFormDialog.vue

@@ -0,0 +1,436 @@
+<template>
+  <el-dialog
+    title="调查表填报"
+    :visible.sync="dialogVisible"
+    width="800px"
+    :close-on-click-modal="false"
+    :show-close="true"
+    append-to-body
+    :modal="false"
+    @close="handleClose"
+  >
+    <el-form ref="surveyForm" :model="form" :rules="rules" label-width="120px">
+      <el-row :gutter="20">
+        <!-- 动态生成表单字段 -->
+        <el-col
+          v-for="(field, index) in formFields"
+          :key="field.prop || field.id || `field-${index}`"
+          :span="field.colSpan || 12"
+        >
+          <el-form-item
+            :label="field.label"
+            :prop="field.prop"
+            :rules="field.rules"
+          >
+            <!-- 文本输入框 -->
+            <el-input
+              v-if="field.type === 'input' || !field.type"
+              v-model="form[field.prop]"
+              :placeholder="field.placeholder || `请输入${field.label}`"
+              :disabled="field.disabled || isViewMode"
+            />
+
+            <!-- 数字输入框 -->
+            <el-input-number
+              v-else-if="field.type === 'number'"
+              v-model="form[field.prop]"
+              :placeholder="field.placeholder || `请输入${field.label}`"
+              :disabled="field.disabled || isViewMode"
+              :min="field.min"
+              :max="field.max"
+              :precision="field.precision"
+              style="width: 100%"
+            />
+
+            <!-- 下拉选择框(字典类型) -->
+            <el-select
+              v-else-if="field.type === 'select' && field.dictType"
+              v-model="form[field.prop]"
+              :placeholder="field.placeholder || `请选择${field.label}`"
+              :disabled="field.disabled || isViewMode"
+              style="width: 100%"
+              :clearable="field.clearable !== false"
+              :multiple="field.multiple"
+            >
+              <el-option
+                v-for="item in getDictOptions(field.dictType)"
+                :key="item.key || item.value"
+                :label="item.name || item.label"
+                :value="item.key || item.value"
+              />
+            </el-select>
+
+            <!-- 下拉选择框(自定义选项) -->
+            <el-select
+              v-else-if="field.type === 'select' && field.options"
+              v-model="form[field.prop]"
+              :placeholder="field.placeholder || `请选择${field.label}`"
+              :disabled="field.disabled || isViewMode"
+              style="width: 100%"
+              :clearable="field.clearable !== false"
+              :multiple="field.multiple"
+            >
+              <el-option
+                v-for="item in field.options"
+                :key="item.value || item.key"
+                :label="item.label || item.name"
+                :value="item.value || item.key"
+              />
+            </el-select>
+
+            <!-- 日期选择器 -->
+            <el-date-picker
+              v-else-if="field.type === 'date'"
+              v-model="form[field.prop]"
+              type="date"
+              :placeholder="field.placeholder || `请选择${field.label}`"
+              :disabled="field.disabled || isViewMode"
+              style="width: 100%"
+              :format="field.format || 'yyyy-MM-dd'"
+              :value-format="field.valueFormat || 'yyyy-MM-dd'"
+            />
+
+            <!-- 日期时间选择器 -->
+            <el-date-picker
+              v-else-if="field.type === 'datetime'"
+              v-model="form[field.prop]"
+              type="datetime"
+              :placeholder="field.placeholder || `请选择${field.label}`"
+              :disabled="field.disabled || isViewMode"
+              style="width: 100%"
+              :format="field.format || 'yyyy-MM-dd HH:mm:ss'"
+              :value-format="field.valueFormat || 'yyyy-MM-dd HH:mm:ss'"
+            />
+
+            <!-- 年份选择器 -->
+            <el-date-picker
+              v-else-if="field.type === 'year'"
+              v-model="form[field.prop]"
+              type="year"
+              :placeholder="field.placeholder || `请选择${field.label}`"
+              :disabled="field.disabled || isViewMode"
+              style="width: 100%"
+              :format="field.format || 'yyyy'"
+              :value-format="field.valueFormat || 'yyyy'"
+            />
+
+            <!-- 文本域 -->
+            <el-input
+              v-else-if="field.type === 'textarea'"
+              v-model="form[field.prop]"
+              type="textarea"
+              :rows="field.rows || 3"
+              :placeholder="field.placeholder || `请输入${field.label}`"
+              :disabled="field.disabled || isViewMode"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <div slot="footer" class="dialog-footer">
+      <el-button type="primary" @click="handleSave">保存</el-button>
+      <el-button @click="handleCancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  import { Message } from 'element-ui'
+  import { dictMixin } from '@/mixins/useDict'
+
+  export default {
+    name: 'SurveyFormDialog',
+    mixins: [dictMixin],
+    props: {
+      visible: {
+        type: Boolean,
+        default: false,
+      },
+      surveyData: {
+        type: Object,
+        default: () => ({}),
+      },
+      // 表单字段配置
+      // 格式: [
+      //   {
+      //     prop: 'institutionName', // 字段属性名
+      //     label: '机构名称', // 字段标签
+      //     type: 'input', // 字段类型: input, select, date, number, textarea等
+      //     colSpan: 12, // 列宽,默认12(占一半)
+      //     dictType: 'institutionNature', // 字典类型(如果type为select且使用字典)
+      //     options: [], // 自定义选项(如果type为select且不使用字典)
+      //     placeholder: '请输入机构名称',
+      //     rules: [], // 验证规则
+      //     defaultValue: '', // 默认值
+      //     disabled: false, // 是否禁用
+      //     clearable: true, // 是否可清空
+      //     multiple: false, // 是否多选
+      //   }
+      // ]
+      formFields: {
+        type: Array,
+        default: () => [],
+      },
+      // 是否查看模式
+      isViewMode: {
+        type: Boolean,
+        default: false,
+      },
+    },
+    data() {
+      return {
+        dialogVisible: false,
+        form: {},
+        rules: {},
+        dictData: {}, // 初始化字典数据对象
+      }
+    },
+    computed: {
+      // 计算需要获取的字典类型
+      dictTypes() {
+        const types = new Set()
+        this.formFields.forEach((field) => {
+          if (field.type === 'select' && field.dictType) {
+            types.add(field.dictType)
+          }
+        })
+        return Array.from(types)
+      },
+    },
+    watch: {
+      visible: {
+        handler(newVal) {
+          this.dialogVisible = newVal
+          if (newVal) {
+            // 弹窗打开时初始化表单
+            this.initForm()
+          }
+        },
+        immediate: true,
+      },
+      dialogVisible(newVal) {
+        if (!newVal) {
+          this.$emit('update:visible', false)
+        }
+      },
+      formFields: {
+        handler() {
+          // 字段配置变化时重新初始化
+          if (this.dialogVisible) {
+            this.initForm()
+          }
+        },
+        deep: true,
+      },
+    },
+    created() {
+      // 初始化字典数据
+      this.initDictData()
+    },
+    methods: {
+      // 初始化字典数据
+      initDictData() {
+        if (this.dictTypes.length > 0) {
+          // 初始化字典数据对象
+          this.dictTypes.forEach((type) => {
+            if (!this.dictData[type]) {
+              this.$set(this.dictData, type, [])
+            }
+          })
+          // 调用父级 mixin 的方法获取字典数据
+          if (this.dictTypes.length > 0) {
+            this.getDictType()
+          }
+        }
+      },
+      // 获取字典选项
+      getDictOptions(dictType) {
+        if (!this.dictData || !this.dictData[dictType]) {
+          return []
+        }
+        return this.dictData[dictType] || []
+      },
+      // 初始化表单
+      initForm() {
+        const form = {}
+        const rules = {}
+
+        // 如果没有传入字段配置,使用默认配置
+        const fields =
+          this.formFields && this.formFields.length > 0
+            ? this.formFields
+            : this.getDefaultFormFields()
+
+        fields.forEach((field) => {
+          // 初始化表单值
+          if (this.surveyData && this.surveyData[field.prop] !== undefined) {
+            // 优先使用传入的数据
+            form[field.prop] = this.surveyData[field.prop]
+          } else if (field.defaultValue !== undefined) {
+            // 其次使用默认值
+            form[field.prop] = field.defaultValue
+          } else {
+            // 最后使用空值
+            form[field.prop] = field.multiple ? [] : ''
+          }
+
+          // 初始化验证规则
+          if (field.rules && Array.isArray(field.rules)) {
+            rules[field.prop] = field.rules
+          } else if (field.required) {
+            // 如果字段标记为必填,自动添加必填验证
+            rules[field.prop] = [
+              {
+                required: true,
+                message: `请输入${field.label}`,
+                trigger: field.type === 'select' ? 'change' : 'blur',
+              },
+            ]
+          }
+        })
+
+        this.form = form
+        this.rules = rules
+
+        // 初始化字典数据
+        this.initDictData()
+      },
+      // 获取默认表单字段配置(兼容旧版本)
+      getDefaultFormFields() {
+        return [
+          {
+            prop: 'institutionName',
+            label: '机构名称',
+            type: 'input',
+            colSpan: 12,
+            defaultValue: '幼儿园基本情况',
+            required: true,
+          },
+          {
+            prop: 'institutionNature',
+            label: '机构性质',
+            type: 'select',
+            colSpan: 12,
+            dictType: 'institutionNature', // 字典类型
+            defaultValue: '公办',
+            required: true,
+          },
+          {
+            prop: 'institutionLevel',
+            label: '机构评定等级',
+            type: 'select',
+            colSpan: 12,
+            dictType: 'institutionLevel', // 字典类型
+            defaultValue: '省一级',
+            required: true,
+          },
+          {
+            prop: 'educationMode',
+            label: '机构办学方式',
+            type: 'select',
+            colSpan: 12,
+            dictType: 'educationMode', // 字典类型
+            defaultValue: '全日制',
+            required: true,
+          },
+          {
+            prop: 'institutionAddress',
+            label: '机构地址',
+            type: 'input',
+            colSpan: 12,
+            required: true,
+          },
+          {
+            prop: 'formFiller',
+            label: '机构填表人',
+            type: 'input',
+            colSpan: 12,
+            required: true,
+          },
+          {
+            prop: 'financialManager',
+            label: '机构财务负责人',
+            type: 'input',
+            colSpan: 12,
+            required: true,
+          },
+          {
+            prop: 'contactPhone',
+            label: '机构联系电话',
+            type: 'input',
+            colSpan: 12,
+            required: true,
+            rules: [
+              {
+                required: true,
+                message: '请输入机构联系电话',
+                trigger: 'blur',
+              },
+              {
+                pattern: /^1[3-9]\d{9}$/,
+                message: '请输入正确的手机号码',
+                trigger: 'blur',
+              },
+            ],
+          },
+          {
+            prop: 'formFillDate',
+            label: '机构填表日期',
+            type: 'date',
+            colSpan: 12,
+            required: true,
+          },
+        ]
+      },
+      handleClose() {
+        this.dialogVisible = false
+        this.$emit('update:visible', false)
+      },
+      handleCancel() {
+        this.handleClose()
+      },
+      handleSave() {
+        this.$refs.surveyForm.validate((valid) => {
+          if (valid) {
+            // 保存逻辑
+            console.log('保存表单数据:', this.form)
+            Message.success('保存成功')
+            // 可以在这里触发保存事件,将数据传递给父组件
+            this.$emit('save', { ...this.form })
+            this.handleClose()
+          } else {
+            Message.error('请完善表单信息')
+            return false
+          }
+        })
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss">
+  .dialog-footer {
+    text-align: center;
+    .el-button {
+      margin: 0 10px;
+    }
+  }
+
+  ::v-deep .el-dialog__header {
+    padding: 20px 20px 10px;
+    .el-dialog__title {
+      font-size: 18px;
+      font-weight: 600;
+      color: #303133;
+    }
+  }
+
+  ::v-deep .el-form-item {
+    margin-bottom: 20px;
+    .el-form-item__label {
+      // color: #409eff;
+      font-weight: 500;
+    }
+  }
+</style>

+ 31 - 3
src/views/EntDeclaration/auditTaskManagement/taskFillIn.vue

@@ -97,14 +97,15 @@
             name="costSurvey"
           >
             <cost-survey-tab
-              :paginated-data="paginatedData"
-              :pagination="pagination"
+              :paginated-data="formData.paginatedData"
+              :pagination="costSurveyPagination"
               :is-view-mode="isViewMode"
               @handle-modify="handleModify"
               @handle-data-download="handleDataDownload"
               @handle-data-upload="handleDataUpload"
               @handle-preview="handlePreview"
-              @handlePageChange="handlePageChange"
+              @handle-page-change="handleCostSurveyPageChange"
+              @handle-size-change="handleCostSurveySizeChange"
             />
           </el-tab-pane>
 
@@ -342,6 +343,7 @@
         projectId: '', // 项目ID
         taskId: '', // 任务ID
         auditedUnitId: '', // 被监审单位ID
+        currentNode: '', // 当前节点
         // 当前激活的标签页
         activeTab: 'projectInfo',
         // 加载状态管理
@@ -485,6 +487,32 @@
             feedbackMaterials: [], // 被监审单位上传的反馈文件
           },
           messageNotice: [], // 消息通知列表
+          paginatedData: [
+            {
+              name: '封面',
+              dataType: '模版定制',
+              tableType: '单记录',
+              isRequired: '是',
+              isUploaded: false,
+              isDisabled: false,
+            },
+            {
+              name: '企业基本情况调查表',
+              dataType: '模版定制',
+              tableType: '固定表',
+              isRequired: '是',
+              isUploaded: true,
+              isDisabled: false,
+            },
+            {
+              name: '企业成本费用调查表',
+              dataType: '模版定制',
+              tableType: '动态表',
+              isRequired: '是',
+              isUploaded: true,
+              isDisabled: false,
+            },
+          ],
         },
         // 监审地区级联选择器
         regionOptions: [

+ 267 - 0
src/views/costAudit/auditInfo/auditManage/collectiveMain.vue

@@ -5,6 +5,7 @@
         <span>集体审议</span>
       </div>
       <div class="collective-header-right">
+        <el-button type="primary" @click="handlePrint">补充资料</el-button>
         <el-button type="primary" @click="handleAddRecord">新增记录</el-button>
       </div>
     </div>
@@ -267,6 +268,59 @@
         </el-button>
       </div>
     </el-dialog>
+
+    <!-- 补充资料弹窗 -->
+    <el-dialog
+      :visible.sync="showSupplementDialog"
+      title="补充资料"
+      width="600px"
+      :modal="false"
+      custom-class="supplement-dialog"
+    >
+      <div class="supplement-dialog-content">
+        <div class="supplement-form-item">
+          <label class="supplement-form-label required">补充意见:</label>
+          <el-input
+            v-model="additionalParams.content"
+            type="textarea"
+            :rows="6"
+            placeholder="请输入补充意见"
+            maxlength="500"
+            show-word-limit
+            class="supplement-textarea"
+          />
+        </div>
+        <div class="supplement-form-item">
+          <label class="supplement-form-label required">选择子单位:</label>
+          <el-select
+            v-model="additionalParams.selectedSubUnits"
+            multiple
+            collapse-tags
+            placeholder="请选择子单位"
+            class="supplement-select"
+            filterable
+          >
+            <el-option
+              v-for="unit in subUnitList"
+              :key="unit.id"
+              :label="unit.name"
+              :value="unit.id"
+            />
+          </el-select>
+        </div>
+        <div class="supplement-form-item">
+          <label class="supplement-form-label required">发送方式:</label>
+          <el-checkbox-group v-model="additionalParams.sendType">
+            <el-checkbox label="site">站内消息</el-checkbox>
+            <el-checkbox label="sms">短信通知</el-checkbox>
+          </el-checkbox-group>
+        </div>
+      </div>
+      <div slot="footer" class="supplement-dialog-footer">
+        <el-button @click="showSupplementDialog = false">取消</el-button>
+        <el-button type="primary" @click="submitSupplement">发送</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 <script>
@@ -275,7 +329,9 @@
     updateCollectiveDeliberate,
     deleteCollectiveDeliberate,
     getCollectiveDeliberateList,
+    getSubUnitList,
   } from '@/api/audit/collective'
+  import { getReviewTask } from '@/api/audit/reviewTask'
   export default {
     name: 'CollectiveMain',
     components: {},
@@ -303,6 +359,7 @@
         recordList: [],
         // 弹窗显示状态
         showRecordDialog: false,
+        showSupplementDialog: false,
         // 表单数据
         formData: {
           id: '',
@@ -323,6 +380,14 @@
         fileList: [],
         // 当前操作类型:add/edit
         operationType: 'add',
+        // 补充资料弹窗数据
+        additionalParams: {
+          content: '',
+          sendType: [],
+          selectedSubUnits: [],
+        },
+        // 子单位列表
+        subUnitList: [],
         // 模拟用户列表数据
         userList: [
           { id: 1, name: '张三' },
@@ -477,6 +542,120 @@
         this.formData.auditedUnit = 'XX有限公司'
       },
 
+      // 补充资料
+      handlePrint() {
+        this.additionalParams = {
+          content: '',
+          sendType: [],
+          selectedSubUnits: [],
+        }
+        this.loadSubUnitList()
+        this.showSupplementDialog = true
+      },
+
+      // 加载子单位列表
+      async loadSubUnitList() {
+        if (!this.id) {
+          return
+        }
+        try {
+          const res = await getSubUnitList({ taskId: this.id })
+          if (res && res.code === 200 && res.value) {
+            this.subUnitList = Array.isArray(res.value)
+              ? res.value.map((item) => ({
+                  id: item.id || item.unitId,
+                  name: item.name || item.unitName,
+                  taskId: item.taskId || item.childTaskId, // 保存子任务ID
+                }))
+              : []
+          } else {
+            this.subUnitList = []
+          }
+        } catch (error) {
+          console.error('获取子单位列表失败:', error)
+          this.subUnitList = []
+        }
+      },
+
+      // 提交补充资料
+      async submitSupplement() {
+        // 验证补充意见
+        if (
+          !this.additionalParams.content ||
+          !this.additionalParams.content.trim()
+        ) {
+          this.$message.error('请输入补充意见')
+          return
+        }
+
+        // 验证任务ID
+        if (!this.id) {
+          this.$message.error('缺少任务ID')
+          return
+        }
+
+        // 验证选择子单位
+        if (
+          !this.additionalParams.selectedSubUnits ||
+          this.additionalParams.selectedSubUnits.length === 0
+        ) {
+          this.$message.error('请选择子单位')
+          return
+        }
+
+        // 验证发送方式
+        if (
+          !this.additionalParams.sendType ||
+          this.additionalParams.sendType.length === 0
+        ) {
+          this.$message.error('请选择发送方式')
+          return
+        }
+
+        try {
+          // 转换发送方式:site -> 1, sms -> 2
+          const sendTypeMap = {
+            site: '1',
+            sms: '2',
+          }
+          const sendTypeStr = this.additionalParams.sendType
+            .map((type) => sendTypeMap[type])
+            .filter(Boolean)
+            .join(',')
+
+          // 获取子任务ID(选中的子单位ID)
+          const childTaskId = this.additionalParams.selectedSubUnits.join(',')
+
+          const params = {
+            taskId: this.id,
+            processNodeKey: this.currentNode || '',
+            key: 1,
+            sendType: sendTypeStr,
+            content: this.additionalParams.content,
+            childTaskId: childTaskId,
+          }
+
+          const response = await getReviewTask(params)
+
+          if (response && response.code === 200) {
+            this.$message.success(response.message || '补充资料发送成功')
+            // 关闭弹窗
+            this.showSupplementDialog = false
+            // 重置表单数据
+            this.additionalParams = {
+              content: '',
+              sendType: [],
+              selectedSubUnits: [],
+            }
+          } else {
+            this.$message.error(response?.message || '补充资料发送失败')
+          }
+        } catch (error) {
+          console.error('补充资料发送失败:', error)
+          this.$message.error('补充资料发送失败')
+        }
+      },
+
       // 新增记录
       handleAddRecord() {
         this.operationType = 'add'
@@ -983,6 +1162,94 @@
     }
   }
 
+  /* 补充资料弹窗样式优化 */
+  ::v-deep .supplement-dialog {
+    .el-dialog__header {
+      padding: 20px 25px 15px;
+      border-bottom: 1px solid #ebeef5;
+      background-color: #fafafa;
+    }
+
+    .el-dialog__title {
+      font-size: 16px;
+      font-weight: 500;
+      color: #303133;
+    }
+
+    .el-dialog__body {
+      padding: 25px;
+    }
+
+    .el-dialog__footer {
+      padding: 15px 25px 20px;
+      border-top: 1px solid #ebeef5;
+      background-color: #fafafa;
+      text-align: right;
+    }
+  }
+
+  .supplement-dialog-content {
+    padding: 0;
+  }
+
+  .supplement-form-item {
+    display: flex;
+    align-items: flex-start;
+    margin-bottom: 20px;
+  }
+
+  .supplement-form-item:last-child {
+    margin-bottom: 0;
+  }
+
+  .supplement-form-label {
+    display: inline-block;
+    width: 100px;
+    text-align: left;
+    color: #606266;
+    font-size: 14px;
+    line-height: 32px;
+    flex-shrink: 0;
+    margin-right: 12px;
+  }
+
+  .supplement-form-label.required::before {
+    content: '*';
+    color: #f56c6c;
+    margin-right: 4px;
+  }
+
+  .supplement-textarea {
+    flex: 1;
+  }
+
+  .supplement-select {
+    flex: 1;
+    min-width: 300px;
+  }
+
+  .supplement-checkbox-group {
+    display: flex;
+    flex-direction: column;
+    flex: 1;
+  }
+
+  .supplement-checkbox-group .el-checkbox {
+    margin-bottom: 8px;
+  }
+
+  .supplement-checkbox-group .el-checkbox:last-child {
+    margin-bottom: 0;
+  }
+
+  .supplement-dialog-footer {
+    text-align: right;
+  }
+
+  .supplement-dialog-footer .el-button {
+    margin-left: 10px;
+  }
+
   /* 打印样式 */
   @media print {
     .collective {

+ 26 - 6
src/views/costAudit/auditInfo/auditManage/details.vue

@@ -20,31 +20,51 @@
       <!-- 标签页面 -->
       <el-tabs v-model="activeTab" type="card" class="audit-tabs">
         <el-tab-pane label="报送资料" name="submitData">
-          <submit-data :id="id" />
+          <submit-data
+            :id="id"
+            :current-node="currentNode"
+            :current-status="currentStatus"
+          />
         </el-tab-pane>
         <el-tab-pane label="成本调查表" name="costSurvey">
-          <cost-survey :id="id" />
+          <cost-survey
+            :id="id"
+            :current-node="currentNode"
+            :current-status="currentStatus"
+          />
         </el-tab-pane>
         <el-tab-pane
           v-if="currentNode !== 'clcs'"
           label="成本审核"
           name="costAudit"
         >
-          <cost-audit :id="id" />
+          <cost-audit
+            :id="id"
+            :current-node="currentNode"
+            :current-status="currentStatus"
+          />
         </el-tab-pane>
         <el-tab-pane
           v-if="currentNode !== 'clcs'"
           label="工作底稿"
           name="workDraft"
         >
-          <work-draft :id="id" />
+          <work-draft
+            :id="id"
+            :current-node="currentNode"
+            :current-status="currentStatus"
+          />
         </el-tab-pane>
         <el-tab-pane
           v-if="currentNode !== 'clcs'"
           label="提取材料登记"
           name="extractMaterial"
         >
-          <extract-material :id="id" />
+          <extract-material
+            :id="id"
+            :current-node="currentNode"
+            :current-status="currentStatus"
+          />
         </el-tab-pane>
         <el-tab-pane
           v-if="currentNode !== 'clcs' && currentNode !== 'sdsh'"
@@ -54,7 +74,7 @@
           <audit-opinion
             :id="id"
             :current-node="currentNode"
-            :status="currentStatus"
+            :current-status="currentStatus"
             @refresh="handleAuditOpinionRefresh"
             @close="handleClose"
           />

+ 24 - 21
src/views/costAudit/auditInfo/auditManage/submitData.vue

@@ -82,27 +82,26 @@
           </template>
         </el-table-column>
         <el-table-column label="操作" width="200" align="center">
-          <template slot-scope="scope">
-            <template v-if="scope.row.isUpload === '1'">
-              <el-button
-                v-if="
-                  scope.row.auditedStatus === '0' &&
-                  scope.row.currentNode === 'clcs'
-                "
-                type="text"
-                size="small"
-                @click="handleAuditMaterial(scope.row)"
-              >
-                审核
-              </el-button>
-              <el-button
-                type="text"
-                size="small"
-                @click="handleViewDownload(scope.row)"
-              >
-                查看
-              </el-button>
-            </template>
+          <template v-if="scope.row.isUpload === '1'" slot-scope="scope">
+            <el-button
+              v-if="
+                scope.row.auditedStatus == '0' &&
+                currentStatus === '审核中' &&
+                currentNode === 'clcs'
+              "
+              type="text"
+              size="small"
+              @click="handleAuditMaterial(scope.row)"
+            >
+              审核
+            </el-button>
+            <el-button
+              type="text"
+              size="small"
+              @click="handleViewDownload(scope.row)"
+            >
+              查看
+            </el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -176,6 +175,10 @@
         type: String,
         default: '',
       },
+      currentStatus: {
+        type: String,
+        default: '',
+      },
     },
     data() {
       return {

+ 213 - 15
src/views/costAudit/auditInfo/auditManage/workDraft.vue

@@ -1,13 +1,21 @@
 <template>
   <div class="work-draft-container">
-    <ht-editor
-      v-model="workingPaperContent"
-      class="working-paper-editor"
-      height="500px"
-      width="100%"
-      :config="editorConfig"
-      @ready="onEditorReady"
-    />
+    <div class="editor-header">
+      <span class="editor-title">工作底稿在线编辑:</span>
+      <el-button type="primary" size="small" @click="handleOnlineEdit">
+        保存
+      </el-button>
+    </div>
+    <div class="editor-wrapper">
+      <ht-editor
+        v-model="workingPaperContent"
+        class="working-paper-editor"
+        height="500px"
+        width="100%"
+        :config="editorConfig"
+        @ready="onEditorReady"
+      />
+    </div>
     <!-- 工作底稿列表 -->
     <div>
       <el-button type="primary" size="small" @click="handleAddWorkingPaper">
@@ -125,6 +133,7 @@
               format="HH:mm"
               placeholder="开始时间"
               style="flex: 1"
+              @change="handleStartTimeChange"
             />
             <span>-</span>
             <el-time-picker
@@ -132,6 +141,7 @@
               format="HH:mm"
               placeholder="结束时间"
               style="flex: 1"
+              :picker-options="endTimePickerOptions"
             />
           </div>
         </el-form-item>
@@ -180,6 +190,8 @@
     getTaskDraftList,
     addTaskDraft,
     deleteTaskDraft,
+    getTaskDraftOnlineEdit,
+    saveTaskDraftOnlineEdit,
   } from '@/api/audit/taskDraft'
   import { uploadFile } from '@/api/file'
   export default {
@@ -200,7 +212,7 @@
           excludeMenus: ['image', 'video'],
         },
         // 工作底稿数据
-        workingPaperContent: '工作底稿内容将在这里展示。',
+        workingPaperContent: '',
         // 工作底稿记录列表
         workingPaperRecords: [],
         // 工作底稿弹窗
@@ -232,10 +244,97 @@
         },
       }
     },
+    computed: {
+      // 结束时间选择器的配置,限制结束时间不能小于开始时间
+      endTimePickerOptions() {
+        return {
+          selectableRange: this.getEndTimeSelectableRange(),
+        }
+      },
+    },
+    watch: {
+      id: {
+        handler(newVal) {
+          if (newVal) {
+            this.getWorkingPaperRecords()
+            this.getWorkingPaperContent()
+          }
+        },
+        immediate: true,
+      },
+    },
     mounted() {
-      this.getWorkingPaperRecords()
+      if (this.id) {
+        this.getWorkingPaperRecords()
+        this.getWorkingPaperContent()
+      }
     },
     methods: {
+      // 获取结束时间可选择的范围
+      getEndTimeSelectableRange() {
+        if (!this.workingPaperForm.startTime) {
+          // 如果没有开始时间,可以选择所有时间
+          return '00:00:00 - 23:59:59'
+        }
+        // 获取开始时间的小时和分钟
+        let startHour = 0
+        let startMinute = 0
+        if (this.workingPaperForm.startTime instanceof Date) {
+          startHour = this.workingPaperForm.startTime.getHours()
+          startMinute = this.workingPaperForm.startTime.getMinutes()
+        } else if (typeof this.workingPaperForm.startTime === 'string') {
+          const parts = this.workingPaperForm.startTime.split(':')
+          if (parts.length >= 2) {
+            startHour = parseInt(parts[0]) || 0
+            startMinute = parseInt(parts[1]) || 0
+          }
+        }
+        // 开始时间加1分钟,作为最小可选时间
+        let minHour = startHour
+        let minMinute = startMinute + 1
+        if (minMinute >= 60) {
+          minMinute = 0
+          minHour += 1
+        }
+        if (minHour >= 24) {
+          minHour = 23
+          minMinute = 59
+        }
+        // 格式化为 HH:mm:ss 格式
+        const minTime = `${String(minHour).padStart(2, '0')}:${String(
+          minMinute
+        ).padStart(2, '0')}:00`
+        return `${minTime} - 23:59:59`
+      },
+      // 开始时间变化时的处理
+      handleStartTimeChange() {
+        // 如果结束时间存在且小于开始时间,则清空结束时间或提示
+        if (this.workingPaperForm.endTime && this.workingPaperForm.startTime) {
+          const startTime = this.getTimeMinutes(this.workingPaperForm.startTime)
+          const endTime = this.getTimeMinutes(this.workingPaperForm.endTime)
+          if (endTime <= startTime) {
+            this.$message.warning('结束时间不能小于或等于开始时间,请重新选择')
+            this.workingPaperForm.endTime = null
+          }
+        }
+      },
+      // 获取时间的总分钟数(用于比较)
+      getTimeMinutes(time) {
+        if (!time) return 0
+        let hours = 0
+        let minutes = 0
+        if (time instanceof Date) {
+          hours = time.getHours()
+          minutes = time.getMinutes()
+        } else if (typeof time === 'string') {
+          const parts = time.split(':')
+          if (parts.length >= 2) {
+            hours = parseInt(parts[0]) || 0
+            minutes = parseInt(parts[1]) || 0
+          }
+        }
+        return hours * 60 + minutes
+      },
       // 获取工作底稿列表
       async getWorkingPaperRecords() {
         if (!this.id) {
@@ -287,6 +386,59 @@
         console.log('编辑器已就绪', editor)
         // 可以在这里获取编辑器实例,进行更多操作
       },
+      // 获取工作底稿在线编辑内容
+      async getWorkingPaperContent() {
+        if (!this.id) {
+          return
+        }
+        try {
+          const res = await getTaskDraftOnlineEdit({ taskId: this.id })
+          if (res && res.code === 200 && res.value) {
+            // 回显内容到编辑器
+            this.workingPaperContent = res.value.content || ''
+          } else {
+            // 如果没有数据,初始化为空
+            this.workingPaperContent = ''
+          }
+        } catch (error) {
+          console.error('获取工作底稿在线编辑内容失败:', error)
+          this.workingPaperContent = ''
+        }
+      },
+      // 保存工作底稿在线编辑内容
+      async handleOnlineEdit() {
+        if (!this.id) {
+          this.$message.warning('缺少任务ID')
+          return
+        }
+        try {
+          // 获取当前时间,格式化为 yyyy-MM-dd HH:mm:ss
+          const now = new Date()
+          const year = now.getFullYear()
+          const month = String(now.getMonth() + 1).padStart(2, '0')
+          const day = String(now.getDate()).padStart(2, '0')
+          const hours = String(now.getHours()).padStart(2, '0')
+          const minutes = String(now.getMinutes()).padStart(2, '0')
+          const seconds = String(now.getSeconds()).padStart(2, '0')
+          const updateTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+
+          const params = {
+            taskId: this.id,
+            content: this.workingPaperContent || '',
+            updateTime: updateTime,
+          }
+
+          const res = await saveTaskDraftOnlineEdit(params)
+          if (res && res.code === 200) {
+            this.$message.success(res.message || '保存成功')
+          } else {
+            this.$message.error(res.message || '保存失败')
+          }
+        } catch (error) {
+          console.error('保存工作底稿在线编辑内容失败:', error)
+          this.$message.error('保存失败')
+        }
+      },
       // 工作底稿操作
       handleAddWorkingPaper() {
         this.isEditWorkingPaper = false
@@ -423,6 +575,23 @@
         try {
           await this.$refs.workingPaperForm.validate()
 
+          // 验证时间范围
+          if (
+            this.workingPaperForm.startTime &&
+            this.workingPaperForm.endTime
+          ) {
+            const startMinutes = this.getTimeMinutes(
+              this.workingPaperForm.startTime
+            )
+            const endMinutes = this.getTimeMinutes(
+              this.workingPaperForm.endTime
+            )
+            if (endMinutes <= startMinutes) {
+              this.$message.error('结束时间不能小于或等于开始时间')
+              return
+            }
+          }
+
           // 格式化日期
           const auditDate = new Date(this.workingPaperForm.auditDate)
           const formattedDate = `${auditDate.getFullYear()}-${String(
@@ -672,12 +841,41 @@
   }
 </script>
 
-<style scoped>
-  /* .work-draft-container {
-    padding: 20px;
-  } */
+<style scoped lang="scss">
+  .work-draft-container {
+    width: 100%;
+  }
 
-  .working-paper-editor {
+  .editor-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
     margin-bottom: 20px;
   }
+
+  .editor-title {
+    font-size: 16px;
+    font-weight: bold;
+  }
+
+  .editor-wrapper {
+    width: 100%;
+    margin-bottom: 20px;
+  }
+
+  .working-paper-editor {
+    width: 100% !important;
+  }
+
+  :deep(.inputs.ht-form-inputs__inline) {
+    width: 100%;
+  }
+
+  :deep(.ht-editor) {
+    width: 100% !important;
+  }
+
+  :deep(.ht-container) {
+    width: 100% !important;
+  }
 </style>

+ 22 - 488
src/views/costAudit/projectInfo/auditProjectManage/memoManage/index.vue

@@ -8,6 +8,25 @@
           <div class="calendar-table-layout">
             <!-- 左侧日历组件 -->
             <div class="element-calendar-container">
+              <div class="calendar-header">
+                <el-button
+                  type="text"
+                  class="calendar-btn"
+                  @click="handlePrevMonth"
+                >
+                  <i class="el-icon-arrow-left"></i>
+                </el-button>
+                <span class="month-text">
+                  {{ setCalendarTitle() }}
+                </span>
+                <el-button
+                  type="text"
+                  class="calendar-btn"
+                  @click="handleNextMonth"
+                >
+                  <i class="el-icon-arrow-right"></i>
+                </el-button>
+              </div>
               <el-calendar v-model="selectedDate" :first-day-of-week="0">
                 <template slot="dateCell" slot-scope="{ date, data }">
                   <el-tooltip placement="top">
@@ -347,6 +366,8 @@
     computed: {},
     watch: {},
     mounted() {
+      this.$el.querySelector('div.el-calendar__header').remove()
+      this.getAuditTaskList()
       this.initCalendarData()
     },
     methods: {},
@@ -354,492 +375,5 @@
 </script>
 
 <style scoped lang="scss">
-  .memo-management-container {
-    background-color: #fff;
-    padding: 20px;
-    overflow-y: auto;
-
-    .page-header-wrapper {
-      .page-header {
-        margin-bottom: 20px;
-        padding-bottom: 10px;
-        border-bottom: 1px solid #e4e7ed;
-
-        .page-title {
-          font-size: 18px;
-          font-weight: 600;
-          color: #303133;
-          margin: 0;
-          font-weight: 600;
-        }
-
-        .header-helper {
-          display: inline-block;
-          width: 0;
-          height: 0;
-          visibility: hidden;
-        }
-      }
-    }
-
-    .tab-switch-container {
-      margin-bottom: 20px;
-      margin-top: 10px;
-    }
-
-    .calendar-table-layout {
-      display: flex;
-      gap: 20px;
-    }
-
-    .calendar-table-layout .element-calendar-container {
-      flex: 0 0 45%;
-      min-width: 0;
-      margin-bottom: 0;
-      height: 650px;
-    }
-
-    .calendar-table-layout .memo-table-container {
-      flex: 0 0 55%;
-    }
-
-    @media (max-width: 1200px) {
-      .calendar-table-layout {
-        flex-direction: column;
-      }
-
-      .calendar-table-layout .element-calendar-container {
-        flex: none;
-        width: 100%;
-        margin-bottom: 20px;
-      }
-    }
-
-    .calendar-view-container {
-      margin-bottom: 0;
-      background-color: #fff;
-      border-radius: 8px;
-      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
-      overflow: hidden;
-
-      .calendar-header-bar {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        margin-bottom: 0;
-        padding: 15px 20px;
-        background-color: #fff;
-        border-bottom: 1px solid #e4e7ed;
-      }
-
-      .current-month-text {
-        font-size: 18px;
-        font-weight: 500;
-        color: #303133;
-      }
-
-      .calendar-grid-wrapper {
-        border: none;
-        border-radius: 0;
-
-        .calendar-weekdays-header {
-          display: grid;
-          grid-template-columns: repeat(7, 1fr);
-          background-color: #fafafa;
-          border-bottom: 1px solid #e4e7ed;
-
-          .weekday-item {
-            padding: 8px 0;
-            text-align: center;
-            font-weight: 500;
-            color: #606266;
-            font-size: 13px;
-          }
-        }
-
-        .calendar-days-grid {
-          display: grid;
-          grid-template-columns: repeat(7, 1fr);
-          background-color: #fff;
-
-          .calendar-day-item {
-            padding: 8px 0;
-            border-right: 1px solid #e4e7ed;
-            border-bottom: 1px solid #e4e7ed;
-            min-height: 60px;
-            position: relative;
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            cursor: pointer;
-
-            &:nth-child(7n) {
-              border-right: none;
-            }
-
-            &:last-child {
-              border-bottom: none;
-            }
-
-            &:hover {
-              background-color: #f5f7fa;
-            }
-
-            .day-number {
-              font-size: 14px;
-              font-weight: normal;
-              display: block;
-              text-align: center;
-              width: 24px;
-              height: 24px;
-              line-height: 24px;
-              margin: 2px 0;
-            }
-
-            .lunar-calendar-day {
-              font-size: 11px;
-              color: #909399;
-              display: block;
-              text-align: center;
-              margin-top: 2px;
-            }
-
-            /* 周末样式 */
-            &:nth-child(7n),
-            &:nth-child(7n-6) {
-              .day-number {
-                color: #f56c6c;
-              }
-
-              /* 覆盖当前日期的周末颜色 */
-              &.current-day-highlight .day-number {
-                color: #fff !important;
-              }
-            }
-
-            /* 当前日期高亮 */
-            &.current-day-highlight {
-              .day-number {
-                background-color: #1890ff;
-                color: #fff;
-                border-radius: 50%;
-                font-weight: 500;
-              }
-            }
-
-            /* 事件标记 - 右上角蓝色圆点 */
-            &.has-event-marker {
-              position: relative;
-            }
-
-            &.has-event-marker::after {
-              content: '';
-              display: block;
-              width: 6px;
-              height: 6px;
-              background-color: #1890ff;
-              border-radius: 50%;
-              position: absolute;
-              top: 8px;
-              right: 8px;
-            }
-
-            /* 其他月份日期 */
-            .other-month-day {
-              color: #c0c4cc;
-            }
-
-            /* 事件指示器 */
-            .day-event-indicator {
-              position: absolute;
-              bottom: 4px;
-              width: 100%;
-              display: flex;
-              justify-content: center;
-            }
-          }
-        }
-      }
-    }
-
-    .memo-table-container {
-      .reminder-dot-marker {
-        display: inline-block;
-        width: 10px;
-        height: 10px;
-        border-radius: 50%;
-        vertical-align: middle;
-      }
-
-      .reminder-dot-marker.urgent {
-        background-color: #f56c6c;
-      }
-
-      .reminder-dot-marker.normal {
-        background-color: #909399;
-      }
-    }
-
-    .file-upload-area {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-
-      .file-name-text {
-        color: #409eff;
-        cursor: pointer;
-        flex: 1;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-      }
-    }
-
-    .dialog-footer-area {
-      text-align: right;
-    }
-  }
-
-  .calendar {
-    background-color: #fff;
-    border-radius: 8px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-    overflow: hidden;
-  }
-
-  .calendar_header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: 10px 20px;
-    background-color: #1890ff;
-    color: white;
-  }
-
-  .calendar_header_btn {
-    background: transparent;
-    border: 1px solid rgba(255, 255, 255, 0.3);
-    color: white;
-    padding: 5px 10px;
-    border-radius: 4px;
-    cursor: pointer;
-    transition: all 0.3s;
-  }
-
-  .calendar_header_btn:hover {
-    background: rgba(255, 255, 255, 0.2);
-    border-color: rgba(255, 255, 255, 0.6);
-  }
-
-  /* Element UI 日历样式 */
-  .element-calendar-container {
-    background: #fff;
-    border-radius: 8px;
-    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-    overflow: hidden;
-    padding: 0;
-  }
-
-  .el-calendar {
-    width: 100%;
-    background-color: #fff;
-  }
-
-  .el-calendar__header {
-    margin-bottom: 0;
-    padding: 15px 20px;
-    border-bottom: 1px solid #e4e7ed;
-    background-color: #fff;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-  }
-
-  .el-calendar__title {
-    font-size: 18px;
-    font-weight: 500;
-    color: #303133;
-    text-align: center;
-    flex: 1;
-  }
-
-  .el-calendar__button-group {
-    margin-top: 0;
-    display: flex;
-    gap: 10px;
-  }
-
-  /* 日历按钮样式 */
-  .el-calendar__button-group .el-button {
-    padding: 6px 12px;
-    font-size: 13px;
-    border-radius: 4px;
-  }
-
-  /* 日历单元格样式 */
-  .calendar-cell {
-    height: 50px;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-    transition: all 0.3s;
-    position: relative;
-    padding: 5px;
-  }
-
-  .calendar-cell:hover {
-    background-color: #f5f7fa;
-  }
-
-  /* 日期数字样式 */
-  .calendar-date-number {
-    font-size: 14px;
-    font-weight: normal;
-    margin-bottom: 2px;
-    width: 24px;
-    height: 24px;
-    line-height: 24px;
-    text-align: center;
-  }
-
-  /* 农历信息样式 */
-  .calendar-lunar-info {
-    font-size: 11px;
-    color: #909399;
-    margin-bottom: 2px;
-  }
-
-  /* 节日样式 */
-  .calendar-festival {
-    color: #f56c6c !important;
-    margin-left: 2px;
-  }
-
-  /* 任务触发区域 */
-  .calendar-task-trigger {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-  }
-
-  /* 任务浮层样式 */
-  .calendar-task-popover {
-    font-size: 12px;
-    max-width: 250px;
-    background-color: #262626 !important;
-    color: #fff !important;
-    border: none !important;
-    border-radius: 4px;
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-    padding: 10px;
-  }
-
-  /* 任务浮层内容样式 */
-  .calendar-task-popover .task-item {
-    padding: 5px 0;
-    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
-    margin-bottom: 5px;
-  }
-
-  .calendar-task-popover .task-item:last-child {
-    border-bottom: none;
-  }
-
-  /* 任务时间段样式 */
-  .calendar-task-popover .task-time {
-    color: #909399;
-    font-size: 11px;
-    margin-top: 2px;
-  }
-
-  /* 周末日期样式 */
-  .el-calendar-table__row {
-    > td:nth-child(1),
-    > td:nth-child(7) {
-      .calendar-date-number {
-        color: #fd8c2f;
-      }
-
-      /* 覆盖当前日期的周末颜色 */
-      &.is-today .calendar-date-number {
-        color: #333 !important;
-      }
-    }
-  }
-
-  /* 日历表格样式 */
-  .el-calendar-table {
-    width: 100%;
-    border-collapse: collapse;
-  }
-
-  .el-calendar-table tr {
-    border-bottom: 1px solid #e4e7ed;
-  }
-
-  .el-calendar-table td {
-    border-right: 1px solid #e4e7ed;
-    padding: 0;
-    height: 50px;
-    width: 14.2857%;
-    /* 1/7 width */
-  }
-
-  .el-calendar-table td:last-child {
-    border-right: none;
-  }
-
-  .el-calendar-table tr:last-child td {
-    border-bottom: none;
-  }
-
-  /* 任务提示框样式 */
-  .el-popover {
-    background-color: #262626 !important;
-    color: #fff !important;
-    border: none !important;
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
-    border-radius: 4px !important;
-  }
-
-  /* 提示框内容样式 */
-  .el-popover__title {
-    color: #fff !important;
-    border-bottom: 1px solid #333;
-    margin: 0 -10px 10px !important;
-    padding: 10px;
-  }
-
-  /* 任务指示器 - 右上角蓝色小圆点 */
-  .task-indicator {
-    position: absolute;
-    top: 5px;
-    right: 5px;
-    width: 8px;
-    height: 8px;
-    border-radius: 50%;
-    background-color: #1890ff;
-  }
-
-  /* 隐藏提示框箭头 */
-  .el-popover__popper[x-placement^='top'] .popper__arrow {
-    border-top-color: #262626;
-
-    .el-popover__popper[x-placement^='bottom'] .popper__arrow {
-      border-bottom-color: #262626;
-    }
-
-    /* 事件标记点 */
-    .event-dot {
-      width: 6px;
-      height: 6px;
-      background-color: #1890ff;
-      border-radius: 50%;
-      margin-top: 3px;
-    }
-  }
+  @import './memoManage.scss';
 </style>

+ 480 - 0
src/views/costAudit/projectInfo/auditProjectManage/memoManage/memoManage.scss

@@ -0,0 +1,480 @@
+.memo-management-container {
+  background-color: #fff;
+  padding: 20px;
+  overflow-y: auto;
+
+  .page-header-wrapper {
+    .page-header {
+      margin-bottom: 20px;
+      padding-bottom: 10px;
+      border-bottom: 1px solid #e4e7ed;
+
+      .page-title {
+        font-size: 18px;
+        font-weight: 600;
+        color: #303133;
+        margin: 0;
+        font-weight: 600;
+      }
+
+      .header-helper {
+        display: inline-block;
+        width: 0;
+        height: 0;
+        visibility: hidden;
+      }
+    }
+  }
+
+  .tab-switch-container {
+    margin-bottom: 20px;
+    margin-top: 10px;
+  }
+
+  .calendar-table-layout {
+    display: flex;
+    gap: 20px;
+  }
+
+  .calendar-table-layout .element-calendar-container {
+    flex: 0 0 45%;
+    min-width: 0;
+    margin-bottom: 0;
+    height: 650px;
+  }
+
+  .calendar-table-layout .memo-table-container {
+    flex: 0 0 55%;
+  }
+
+  @media (max-width: 1200px) {
+    .calendar-table-layout {
+      flex-direction: column;
+    }
+
+    .calendar-table-layout .element-calendar-container {
+      flex: none;
+      width: 100%;
+      margin-bottom: 20px;
+    }
+  }
+
+  .calendar-view-container {
+    margin-bottom: 0;
+    background-color: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+    overflow: hidden;
+
+    .calendar-header-bar {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 0;
+      padding: 15px 20px;
+      background-color: #fff;
+      border-bottom: 1px solid #e4e7ed;
+    }
+
+    .current-month-text {
+      font-size: 18px;
+      font-weight: 500;
+      color: #303133;
+    }
+
+    .calendar-grid-wrapper {
+      border: none;
+      border-radius: 0;
+
+      .calendar-weekdays-header {
+        display: grid;
+        grid-template-columns: repeat(7, 1fr);
+        background-color: #fafafa;
+        border-bottom: 1px solid #e4e7ed;
+
+        .weekday-item {
+          padding: 8px 0;
+          text-align: center;
+          font-weight: 500;
+          color: #606266;
+          font-size: 13px;
+        }
+      }
+
+      .calendar-days-grid {
+        display: grid;
+        grid-template-columns: repeat(7, 1fr);
+        background-color: #fff;
+
+        .calendar-day-item {
+          padding: 8px 0;
+          border-right: 1px solid #e4e7ed;
+          border-bottom: 1px solid #e4e7ed;
+          min-height: 60px;
+          position: relative;
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          cursor: pointer;
+
+          &:nth-child(7n) {
+            border-right: none;
+          }
+
+          &:last-child {
+            border-bottom: none;
+          }
+
+          &:hover {
+            background-color: #f5f7fa;
+          }
+
+          .day-number {
+            font-size: 14px;
+            font-weight: normal;
+            display: block;
+            text-align: center;
+            width: 24px;
+            height: 24px;
+            line-height: 24px;
+            margin: 2px 0;
+          }
+
+          .lunar-calendar-day {
+            font-size: 11px;
+            color: #909399;
+            display: block;
+            text-align: center;
+            margin-top: 2px;
+          }
+
+          /* 周末样式 */
+          &:nth-child(7n),
+          &:nth-child(7n-6) {
+            .day-number {
+              color: #f56c6c;
+            }
+
+            /* 覆盖当前日期的周末颜色 */
+            &.current-day-highlight .day-number {
+              color: #fff !important;
+            }
+          }
+
+          /* 当前日期高亮 */
+          &.current-day-highlight {
+            .day-number {
+              background-color: #1890ff;
+              color: #fff;
+              border-radius: 50%;
+              font-weight: 500;
+            }
+          }
+
+          /* 事件标记 - 右上角蓝色圆点 */
+          &.has-event-marker {
+            position: relative;
+          }
+
+          &.has-event-marker::after {
+            content: '';
+            display: block;
+            width: 6px;
+            height: 6px;
+            background-color: #1890ff;
+            border-radius: 50%;
+            position: absolute;
+            top: 8px;
+            right: 8px;
+          }
+
+          /* 其他月份日期 */
+          .other-month-day {
+            color: #c0c4cc;
+          }
+
+          /* 事件指示器 */
+          .day-event-indicator {
+            position: absolute;
+            bottom: 4px;
+            width: 100%;
+            display: flex;
+            justify-content: center;
+          }
+        }
+      }
+    }
+  }
+
+  .memo-table-container {
+    .reminder-dot-marker {
+      display: inline-block;
+      width: 10px;
+      height: 10px;
+      border-radius: 50%;
+      vertical-align: middle;
+    }
+
+    .reminder-dot-marker.urgent {
+      background-color: #f56c6c;
+    }
+
+    .reminder-dot-marker.normal {
+      background-color: #909399;
+    }
+  }
+
+  .file-upload-area {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .file-name-text {
+      color: #409eff;
+      cursor: pointer;
+      flex: 1;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+  }
+
+  .dialog-footer-area {
+    text-align: right;
+  }
+}
+
+.calendar {
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+}
+
+.calendar_header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px 20px;
+  background-color: #1890ff;
+  color: white;
+}
+
+.calendar_header_btn {
+  background: transparent;
+  border: 1px solid rgba(255, 255, 255, 0.3);
+  color: white;
+  padding: 5px 10px;
+  border-radius: 4px;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.calendar_header_btn:hover {
+  background: rgba(255, 255, 255, 0.2);
+  border-color: rgba(255, 255, 255, 0.6);
+}
+
+/* Element UI 日历样式 */
+.element-calendar-container {
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+  padding: 0;
+}
+
+.el-calendar {
+  width: 100%;
+  background-color: #fff;
+}
+
+.el-calendar__header {
+  margin-bottom: 0;
+  padding: 15px 20px;
+  border-bottom: 1px solid #e4e7ed;
+  background-color: #fff;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.el-calendar__title {
+  font-size: 18px;
+  font-weight: 500;
+  color: #303133;
+  text-align: center;
+  flex: 1;
+}
+
+.el-calendar__button-group {
+  margin-top: 0;
+  display: flex;
+  gap: 10px;
+}
+
+/* 日历按钮样式 */
+.el-calendar__button-group .el-button {
+  padding: 6px 12px;
+  font-size: 13px;
+  border-radius: 4px;
+}
+
+/* 日历单元格样式 */
+.calendar-cell {
+  height: 50px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  transition: all 0.3s;
+  position: relative;
+  padding: 5px;
+}
+
+.calendar-cell:hover {
+  background-color: #f5f7fa;
+}
+
+/* 日期数字样式 */
+.calendar-date-number {
+  font-size: 14px;
+  font-weight: normal;
+  margin-bottom: 2px;
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+  text-align: center;
+}
+
+/* 农历信息样式 */
+.calendar-lunar-info {
+  font-size: 11px;
+  color: #909399;
+  margin-bottom: 2px;
+}
+
+/* 节日样式 */
+.calendar-festival {
+  color: #f56c6c !important;
+  margin-left: 2px;
+}
+
+/* 任务触发区域 */
+.calendar-task-trigger {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+/* 任务浮层样式 */
+.calendar-task-popover {
+  font-size: 12px;
+  max-width: 250px;
+  background-color: #262626 !important;
+  color: #fff !important;
+  border: none !important;
+  border-radius: 4px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  padding: 10px;
+}
+
+/* 任务浮层内容样式 */
+.calendar-task-popover .task-item {
+  padding: 5px 0;
+  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+  margin-bottom: 5px;
+}
+
+.calendar-task-popover .task-item:last-child {
+  border-bottom: none;
+}
+
+/* 任务时间段样式 */
+.calendar-task-popover .task-time {
+  color: #909399;
+  font-size: 11px;
+  margin-top: 2px;
+}
+.calendar-header {
+  width: 95%;
+  margin: 15px auto 0;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  text-align: center;
+  background: #f0f4fd;
+  padding: 5px 0;
+}
+.calendar-btn {
+  margin: 0 20px;
+  cursor: pointer;
+  font-size: 20px;
+  color: #606266;
+  transition: color 0.3s ease;
+  &:hover {
+    color: #409eff;
+  }
+}
+/* 周末日期样式 */
+.el-calendar-table__row {
+  > td:nth-child(1),
+  > td:nth-child(7) {
+    .calendar-date-number {
+      color: #fd8c2f;
+    }
+
+    /* 覆盖当前日期的周末颜色 */
+    &.is-today .calendar-date-number {
+      color: #333 !important;
+    }
+  }
+}
+
+/* 日历表格样式 */
+.el-calendar-table {
+  width: 100%;
+  border-collapse: collapse;
+}
+
+.el-calendar-table tr {
+  border-bottom: 1px solid #e4e7ed;
+}
+
+.el-calendar-table td {
+  border-right: 1px solid #e4e7ed;
+  padding: 0;
+  height: 50px;
+  width: 14.2857%;
+  /* 1/7 width */
+}
+
+.el-calendar-table td:last-child {
+  border-right: none;
+}
+
+.el-calendar-table tr:last-child td {
+  border-bottom: none;
+}
+
+/* 提示框内容样式 */
+.el-popover__title {
+  color: #fff !important;
+  border-bottom: 1px solid #333;
+  margin: 0 -10px 10px !important;
+  padding: 10px;
+}
+
+/* 任务指示器 - 右上角蓝色小圆点 */
+.task-indicator {
+  position: absolute;
+  top: 5px;
+  right: 5px;
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  background-color: #1890ff;
+}

+ 19 - 14
src/views/costAudit/projectInfo/auditProjectManage/memoManage/memoManageMixin.js

@@ -141,6 +141,7 @@ export const memoManageMixin = {
       fileList: [],
       isEditDialogOpen: false,
       auditTaskList: [],
+      lunarInfo: {},
     }
   },
   computed: {
@@ -154,14 +155,14 @@ export const memoManageMixin = {
   },
   watch: {
     // // 监听选中日期变化,更新搜索参数
-    // selectedDate: {
-    //   handler(newVal) {
-    //     if (newVal) {
-    //       const monthMoment = moment(newVal).startOf('month')
-    //     }
-    //   },
-    //   deep: true,
-    // },
+    selectedDate: {
+      handler(newVal) {
+        if (newVal) {
+          this.lunarInfo = this.getLunarInfo(this.selectedDate)
+        }
+      },
+      deep: true,
+    },
   },
   methods: {
     // 根据提醒类型获取对应的颜色
@@ -298,9 +299,9 @@ export const memoManageMixin = {
         lunarDate: '超出转换范围',
         festival: null,
         lunarFestival: null,
-        lYear: null,
-        lMonth: null,
-        lDay: null,
+        lYear: year,
+        lMonth: month,
+        lDay: day,
         Animal: null,
         IMonthCn: '',
         IDayCn: '',
@@ -326,14 +327,14 @@ export const memoManageMixin = {
     },
 
     // 上一个月
-    prevMonth() {
+    handlePrevMonth() {
       this.selectedDate = moment(this.selectedDate)
         .subtract(1, 'month')
         .toDate()
     },
 
     // 下一个月
-    nextMonth() {
+    handleNextMonth() {
       this.selectedDate = moment(this.selectedDate).add(1, 'month').toDate()
     },
     // 获取备忘录列表
@@ -383,6 +384,9 @@ export const memoManageMixin = {
     },
     // 初始化日历相关数据
     initCalendarData() {
+      this.selectedDate = new Date()
+      console.log('初始化日历数据', this.selectedDate)
+      this.lunarInfo = this.getLunarInfo(this.selectedDate)
       this.handleSearch()
     },
     onTabChange(tab) {
@@ -565,7 +569,8 @@ export const memoManageMixin = {
     // 设置日历标题
     setCalendarTitle() {
       // 可以在这里添加设置日历标题的逻辑
-      console.log(`当前显示: ${this.currentYear}年${this.currentMonth}月`)
+      let lunarInfo = this.lunarInfo
+      return `${lunarInfo.lYear}年${lunarInfo.lMonth}月 农历${lunarInfo.gzYear}年【${lunarInfo.Animal}】`
     },
   },
 }

+ 252 - 131
src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/auditNoticeTab.vue

@@ -43,6 +43,14 @@
           <template #enterpriseId="{ row }">
             {{ getEnterpriseName(row) }}
           </template>
+          <template #generateTime="{ row }">
+            <div>
+              {{ row.generateTime ? row.generateTime.split(' ')[0] : '' }}
+            </div>
+            <div>
+              {{ row.generateTime ? row.generateTime.split(' ')[1] : '' }}
+            </div>
+          </template>
           <template #scanDocumentUrl="scope">
             <el-button
               v-if="!isView"
@@ -84,7 +92,7 @@
               查看附件
             </el-button>
           </template>
-          <template #electronicDocumentUrl="scope">
+          <template #action="scope">
             <el-button
               v-if="!isView"
               type="text"
@@ -138,6 +146,7 @@
         <div class="document-params">
           <h4>文书参数设置:</h4>
           <el-form
+            ref="documentForm"
             v-loading="loading.saveDocument"
             :model="document"
             label-width="170px"
@@ -175,21 +184,22 @@
                 选择文号
               </el-button>
             </el-form-item>
-            <el-form-item label="被监审单位:" prop="enterpriseId">
-              <el-select
-                v-model="document.enterpriseId"
-                placeholder="请选择被监审单位"
-                style="width: 100%"
-                clearable
-                multiple
-              >
-                <el-option
-                  v-for="item in allUnits"
-                  :key="item.unitId"
-                  :label="item.unitName"
-                  :value="item.unitId"
-                ></el-option>
-              </el-select>
+            <el-form-item label="被监审单位" prop="enterpriseId">
+              <div style="display: flex; align-items: center; gap: 15px">
+                <el-select
+                  v-model="document.enterpriseId"
+                  placeholder="请选择被监审单位"
+                  style="width: 100%"
+                  clearable
+                >
+                  <el-option
+                    v-for="item in allUnits"
+                    :key="item.unitId"
+                    :label="item.unitName"
+                    :value="item.unitId"
+                  ></el-option>
+                </el-select>
+              </div>
             </el-form-item>
             <el-form-item label="是否推送被监审单位:" prop="isPushed">
               <!-- 是否推送被监审单位 -->
@@ -300,11 +310,9 @@
   import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
   import TemplatePreviewEdit from '@/components/costAudit/TemplatePreviewEdit.vue'
   import { getAllUnitList } from '@/api/auditEntityManage'
-  import {
-    getWhCateList,
-    queryByDocumentId,
-  } from '@/api/auditReviewDocManage.js'
+  import { queryByDocumentIdandWhereValue } from '@/api/auditReviewDocManage.js'
   import { getData } from '@/api/auditDocNoManage.js'
+  import { updateScan, downDocument } from '@/api/taskCustomizedRelease.js'
   import {
     addCostProjectDocument,
     updateCostProjectDocument,
@@ -332,17 +340,35 @@
     },
     data() {
       return {
+        isMultipleMode: false,
         dictData: {
           whGenerateType: [],
         },
         activeDocumentTypeId: '',
         document: {
+          createBy: '',
+          createTime: '',
+          documentAlias: '',
           documentId: '',
-          documentWhId: '',
+          documentName: '',
           documentNumber: '',
+          documentType: '',
+          documentWhId: '',
+          electronicDocumentUrl: '',
           enterpriseId: [],
-          dataList: [],
-          isPushed: '1',
+          feedbackDocumentUrl: '',
+          feedbackTime: '',
+          generateTime: '',
+          id: '',
+          isDeleted: '',
+          isPushed: '',
+          orderNum: 0,
+          pkVal: '',
+          projectId: '',
+          pushTime: '',
+          scanDocumentUrl: '',
+          updateBy: '',
+          updateTime: '',
         },
         loading: {
           saveDocument: false,
@@ -354,7 +380,7 @@
         dialogVisible: false,
         dialogTitle: '选择文号',
         documentDialogVisible: false,
-        documentDialogTitle: '编辑监审通知书',
+        documentDialogTitle: '添加监审通知书',
         dialogWidth: '70%',
         fileUrl: '',
         selectDocumentWhData: [],
@@ -495,17 +521,37 @@
 
       // 生成文书
       handleGenerateDocument() {
+        this.documentDialogTitle = '添加监审通知书'
         this.documentDialogVisible = true
         this.activeView = 'form'
         this.document = {
+          createBy: '',
+          createTime: '',
+          documentAlias: '',
           documentId: '',
-          documentWhId: '',
+          documentName: '',
           documentNumber: '',
-          enterpriseId: [],
-          isPushed: '1', // 默认设置为'1'(是)
+          documentType: '',
+          documentWhId: '',
+          electronicDocumentUrl: '',
+          enterpriseId: this.isMultipleMode ? [] : '',
+          feedbackDocumentUrl: '',
+          feedbackTime: '',
+          generateTime: '',
+          id: '',
+          isDeleted: '',
+          isPushed: '1',
+          orderNum: this.documentData.list.length + 1,
+          pkVal: '',
+          projectId: '',
+          pushTime: '',
+          scanDocumentUrl: '',
+          updateBy: '',
+          updateTime: '',
         }
         if (this.activeDocumentTypeId) {
           this.document.documentId = this.activeDocumentTypeId
+          this.handleTemplateChange()
         }
         this.costProjectDocumentFiles = []
       },
@@ -537,14 +583,19 @@
         }
       },
       handleTemplateChange() {
-        this.fileUrl = this.documentData.documentTypes.find(
+        let data = this.documentData.documentTypes.find(
           (item) => item.id === this.document.documentId
-        ).fileUrl
-        this.getDocumentData(this.document.documentId)
+        )
+        this.fileUrl = data.fileUrl
+        this.document.documentName = data.documentName
+        this.getDocumentData()
       },
-      getDocumentData(documentId) {
-        if (documentId) {
-          queryByDocumentId({ documentId }).then((res) => {
+      getDocumentData() {
+        if (this.document.documentId) {
+          queryByDocumentIdandWhereValue({
+            documentId: this.document.documentId,
+            whereValue: this.project.projectId,
+          }).then((res) => {
             this.costDocumentTemplateFiles = res.value || []
           })
         }
@@ -574,76 +625,55 @@
       },
       // 保存文档
       handleSaveDocument() {
-        // 验证是否选择了企业
-        if (
-          !this.document.enterpriseId ||
-          this.document.enterpriseId.length === 0
-        ) {
-          this.$message.error('请至少选择一个被监审单位!')
-          return
-        }
-
-        this.loading.saveDocument = true
-        if (this.document.id) {
-          updateCostProjectDocument({
-            id: this.document.id,
-            // documentAlias: this.document.documentAlias,
-            documentId: this.document.documentId,
-            documentNumber: this.document.documentNumber,
-            documentWhId: this.document.documentWhId,
-            costProjectDocumentFiles: this.costDocumentTemplateFiles,
-            isPushed: this.document.isPushed, // 添加isPushed字段
-            projectId: this.project.projectId,
-            // electronicDocumentUrl: '',
-            enterpriseId: this.document.enterpriseId.join(','), // 保存时转换为逗号分隔的字符串
-            // feedbackDocumentUrl: '',
-            // feedbackTime: '',
-            // generateTime: '',
-          })
-            .then((res) => {
-              this.loading.saveDocument = false
-              this.$message.success('保存成功!')
-              this.documentDialogVisible = false
-              this.activeView = ''
-              this.$emit('refresh', this.project.projectId)
-            })
-            .catch((err) => {
-              this.loading.saveDocument = false
+        // 校验表单
+        this.$refs.documentForm.validate((valid) => {
+          if (!valid) {
+            this.$message.error('请填写必填项!')
+            return false
+          }
+          this.loading.saveDocument = true
+          if (this.document.id) {
+            updateCostProjectDocument({
+              ...this.document,
+              costProjectDocumentFiles: this.costDocumentTemplateFiles,
+              projectId: this.project.projectId,
+              electronicDocumentUrl: this.fileUrl,
+              enterpriseId: this.isMultipleMode
+                ? this.document.enterpriseId.join(',')
+                : this.document.enterpriseId, // 保存时转换为逗号分隔的字符串
             })
-        } else {
-          // 处理多选逻辑,如果选择了多个单位,为每个单位创建一个文档记录
-          const promises = this.document.enterpriseId.map((enterpriseId) => {
-            return addCostProjectDocument({
-              // documentAlias: this.document.documentAlias,
+              .then((res) => {
+                this.loading.saveDocument = false
+                this.$message.success('保存成功!')
+                this.documentDialogVisible = false
+                this.activeView = ''
+                this.$emit('refresh', this.project.projectId)
+              })
+              .catch((err) => {
+                this.loading.saveDocument = false
+              })
+          } else {
+            addCostProjectDocument({
+              ...this.document,
               projectId: this.project.projectId,
-              documentId: this.document.documentId,
-              documentNumber: this.document.documentNumber,
-              documentWhId: this.document.documentWhId,
               costProjectDocumentFiles: this.costDocumentTemplateFiles || [],
-              enterpriseId: enterpriseId,
-              // electronicDocumentUrl: '',
-              // feedbackDocumentUrl: '',
-              // feedbackTime: '',
-              // generateTime: '',
-              isPushed: this.document.isPushed, // 使用isPushed,如果不存在则使用isPushed
-              // orderNum: 0,
-              // pushTime: '',
-              // scanDocumentUrl: '',
+              enterpriseId: this.isMultipleMode
+                ? this.document.enterpriseId.join(',')
+                : this.document.enterpriseId,
+              electronicDocumentUrl: this.fileUrl,
             })
-          })
-
-          Promise.all(promises)
-            .then(() => {
-              this.loading.saveDocument = false
-              this.$message.success('保存成功!')
-              this.documentDialogVisible = false
-              this.activeView = ''
-              this.$emit('refresh', this.project.projectId)
-            })
-            .catch((err) => {
-              this.loading.saveDocument = false
-            })
-        }
+              .then(() => {
+                this.loading.saveDocument = false
+                this.$message.success('保存成功!')
+                this.documentDialogVisible = false
+                this.activeView = ''
+                this.$emit('refresh', this.project.projectId)
+              })
+              .catch((err) => {
+                this.loading.saveDocument = false
+              })
+          }
+        })
       },
       // 处理取消
       handleCancel() {
@@ -716,12 +746,12 @@
             const fileInfo = uploadRes.value
             // 创建更新数据对象
             const updateData = {
-              ...row,
+              id: row.id,
               scanDocumentUrl: fileInfo?.savePath, // 更新扫描件URL
             }
 
             // 第六步:调用更新API
-            await updateCostProjectDocument(updateData)
+            await updateScan(updateData)
 
             // 第七步:更新成功,显示提示并刷新
             this.$message.success('文件上传成功并更新数据!')
@@ -755,20 +785,14 @@
       },
       // 编辑文档
       handleEditDocument(row) {
+        this.documentDialogTitle = '修改监审通知书'
         this.documentDialogVisible = true
         this.activeView = 'form'
         this.loadOpts()
         // 确保enterpriseId是数组格式,处理可能的逗号分隔字符串
-        const enterpriseId = row.enterpriseId
-          ? Array.isArray(row.enterpriseId)
-            ? row.enterpriseId
-            : typeof row.enterpriseId === 'string'
-            ? row.enterpriseId
-                .split(',')
-                .map((id) => id.trim())
-                .filter((id) => id) // 将逗号分隔字符串转换为数组
-            : [row.enterpriseId]
-          : []
+        const enterpriseId = this.isMultipleMode
+          ? row.enterpriseId.split(',')
+          : row.enterpriseId
         this.document = {
           ...row,
           documentId: Number(row.documentId),
@@ -776,10 +800,8 @@
           // 确保isPushed有值,如果row中没有,设置默认值'1'
           isPushed: row.isPushed !== undefined ? row.isPushed : '1',
         }
-        this.fileUrl = this.documentData.documentTypes.find(
-          (item) => item.id === this.document.documentId
-        ).fileUrl
-        this.getDocumentData(this.document.documentId)
+        this.fileUrl = this.document.electronicDocumentUrl
+        this.getDocumentData()
       },
 
       // 签章
@@ -799,27 +821,126 @@
         })
       },
 
+      handleDownloadDocument1(row) {
+        // 显示加载状态
+        this.$loading({
+          lock: true,
+          text: '文件下载中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
+        let fileUrl = window.context.form + row.electronicDocumentUrl
+        let fileName = ''
+        // 从URL中提取文件名
+        const urlParts = fileUrl.split('/')
+        let urlFileName = urlParts[urlParts.length - 1]
+
+        // 处理URL可能包含查询参数的情况
+        if (urlFileName.includes('?')) {
+          urlFileName = urlFileName.split('?')[0]
+        }
+
+        // 检查从URL提取的文件名是否有效
+        if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
+          fileName = urlFileName
+        } else {
+          // URL中无法提取有效文件名时,使用row.documentName作为备选
+          fileName = row.documentName || `监审通知书_${new Date().getTime()}`
+
+          // 确保备选文件名有扩展名
+          if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+            fileName += '.pdf'
+          }
+        }
+        // 创建隐藏的a标签进行下载
+        const link = document.createElement('a')
+        link.style.display = 'none'
+        link.href = fileUrl
+        // 设置下载文件名
+        link.download = fileName
+        document.body.appendChild(link)
+        link.click()
+        document.body.removeChild(link)
+        // 关闭加载状态
+        this.$loading().close()
+      },
       // 下载文档
       handleDownloadDocument(row) {
-        if (!row.electronicDocumentUrl) {
-          this.$message.error('暂无电子文档可供下载!')
-          return
-        }
+        // 显示加载状态
+        this.$loading({
+          lock: true,
+          text: '文件下载中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
 
-        try {
-          // 构建完整的文件URL
-          const fileUrl = row.electronicDocumentUrl.startsWith('http')
-            ? row.electronicDocumentUrl
-            : window.context.form + row.electronicDocumentUrl
+        // 从API中获取文件URL
+        downDocument({
+          id: row.id,
+        })
+          .then((res) => {
+            // 关闭加载状态
+            this.$loading().close()
 
-          // 直接在新窗口打开(浏览器会自动处理下载)
-          window.open(fileUrl, '_blank')
+            // 检查返回结果是否成功
+            if (!res || !res.state) {
+              this.$message.error(
+                `下载失败:${res?.message || '未获取到文件数据'}`
+              )
+              return
+            }
 
-          this.$message.success('文档下载开始!')
-        } catch (error) {
-          console.error('下载失败:', error)
-          this.$message.error('文档下载失败:' + (error.message || '未知错误'))
-        }
+            // 获取文件URL
+            const fileUrl = res.value
+            if (!fileUrl) {
+              this.$message.error('下载失败:未获取到文件URL')
+              return
+            }
+
+            // 优先从URL中提取文件名
+            let fileName = ''
+
+            // 从URL中提取文件名
+            const urlParts = fileUrl.split('/')
+            let urlFileName = urlParts[urlParts.length - 1]
+
+            // 处理URL可能包含查询参数的情况
+            if (urlFileName.includes('?')) {
+              urlFileName = urlFileName.split('?')[0]
+            }
+
+            // 检查从URL提取的文件名是否有效
+            if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
+              fileName = urlFileName
+            } else {
+              // URL中无法提取有效文件名时,使用row.documentName作为备选
+              fileName =
+                row.documentName || `监审通知书_${new Date().getTime()}`
+
+              // 确保备选文件名有扩展名
+              if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+                fileName += '.pdf'
+              }
+            }
+            // 创建隐藏的a标签进行下载
+            const link = document.createElement('a')
+            link.style.display = 'none'
+            link.href = fileUrl
+            // link.href = window.context.form + row.electronicDocumentUrl
+            // 设置下载文件名
+            link.download = fileName
+            document.body.appendChild(link)
+            link.click()
+            document.body.removeChild(link)
+          })
+          .catch((error) => {
+            // 关闭加载状态
+            this.$loading().close()
+            console.error('获取文件URL失败:', error)
+            this.$message.error(
+              `获取下载链接失败: ${error.message || '未知错误'}`
+            )
+          })
       },
     },
   }

+ 2 - 2
src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/index.js

@@ -298,11 +298,11 @@ export const taskMixin = {
             slotName: 'feedbackDocumentUrl',
           },
           {
-            prop: 'electronicDocumentUrl',
+            prop: 'action',
             label: '电子文书',
             width: 200,
             align: 'center',
-            slotName: 'electronicDocumentUrl',
+            slotName: 'action',
           },
         ],
       },

+ 146 - 285
src/views/home/index.vue

@@ -164,6 +164,7 @@
                 type="primary"
                 style="margin-left: 10px"
                 size="small"
+                icon="el-icon-search"
                 @click="searchMemo"
               >
                 查询
@@ -181,17 +182,7 @@
                   >
                     <i class="el-icon-arrow-left"></i>
                   </el-button>
-                  <span class="month-text">
-                    {{ getCustomMonthText(currentDate) }}
-                    <span class="lunar-info">
-                      农历{{
-                        getChineseCalendar(
-                          currentDate.getFullYear(),
-                          currentDate.getMonth() + 1
-                        )
-                      }}年【{{ getChineseZodiac(currentDate.getFullYear()) }}】
-                    </span>
-                  </span>
+                  <span class="month-text">{{ setCalendarTitle() }}年</span>
                   <el-button
                     type="text"
                     class="calendar-btn"
@@ -200,46 +191,71 @@
                     <i class="el-icon-arrow-right"></i>
                   </el-button>
                 </div>
-                <el-calendar ref="calendar" v-model="currentDate">
+                <el-calendar
+                  ref="calendar"
+                  v-model="selectedDate"
+                  :first-day-of-week="0"
+                >
                   <!-- 自定义日期单元格 -->
-                  <template slot="dateCell" slot-scope="{ data }">
-                    <div
-                      class="calendar-day"
-                      :class="{
-                        'has-event': hasEventOnDate(data.day),
-                        selected: data.date === currentDate,
-                        weekend: isWeekend(new Date(data.date)),
-                      }"
-                      @click="handleDateClick(data)"
-                    >
-                      <div class="date-number">
-                        {{ data.day.split('-').slice(2).join('-') }}
-                      </div>
-
-                      <div class="lunar-date">
-                        {{ getLunarDate(data.day) }}
-                      </div>
-
-                      <div
-                        v-if="hasEventOnDate(data.day)"
-                        class="event-dot"
-                      ></div>
-
+                  <template slot="dateCell" slot-scope="{ date, data }">
+                    <el-tooltip placement="top">
                       <div
-                        v-if="hasEventOnDate(data.day)"
-                        v-show="showTooltip && selectedDate === data.day"
-                        class="tooltip"
+                        class="calendar-cell"
+                        @click="handleDateClick(date, data)"
                       >
-                        <div class="tooltip-content">
-                          {{ getEventDescription(data.day) }}
+                        <!-- 公历日期 -->
+                        <div class="calendar-date-number">
+                          {{ data.day.split('-').slice(-1)[0] }}
+                        </div>
+                        <!-- 农历日期和节日 -->
+                        <div class="calendar-lunar-info">
+                          <!-- 公历节日 -->
+                          {{ getLunarInfo(date).IDayCn }}
+                          <span class="calendar-festival">
+                            {{
+                              getLunarInfo(date).festival
+                                ? getLunarInfo(date).festival + ' '
+                                : ''
+                            }}
+                            {{
+                              getLunarInfo(date).lunarFestival
+                                ? getLunarInfo(date).lunarFestival + ' '
+                                : ''
+                            }}
+                            {{
+                              getLunarInfo(date).Term
+                                ? getLunarInfo(date).Term
+                                : ''
+                            }}
+                          </span>
                         </div>
+                        <div
+                          v-if="getTasksByDate(date).length > 0"
+                          class="task-indicator"
+                        ></div>
                       </div>
-                    </div>
+                      <div slot="content">
+                        <template v-if="getTasksByDate(date).length > 0">
+                          <div
+                            v-for="(task, index) in getTasksByDate(date)"
+                            :key="index"
+                            class="task-item"
+                          >
+                            <div class="task-title">
+                              {{ index + 1 }}.{{ task.projectName }}
+                            </div>
+                          </div>
+                        </template>
+                        <template v-else>
+                          <div class="no-tasks">暂无任务安排</div>
+                        </template>
+                      </div>
+                    </el-tooltip>
                   </template>
                 </el-calendar>
               </div>
             </el-col>
-            <el-col :span="11">
+            <el-col :span="10">
               <ul class="memo-list">
                 <li
                   v-for="(item, idx) in memoList"
@@ -251,19 +267,47 @@
                       v-if="item.type === 'warning'"
                       src="@/assets/index_images/index-icon6-light@2x.png"
                       alt=""
+                      style="width: 15px; height: 15px"
                     />
                     <img
                       v-else
                       src="@/assets/index_images/index-icon6@2x.png"
                       alt=""
+                      style="width: 15px; height: 15px"
                     />
                   </div>
                   <div class="memo-content">
-                    <h4>{{ item.title }}</h4>
-                    <p class="memo-desc">{{ item.desc }}</p>
+                    <h4
+                      style="
+                        overflow: hidden;
+                        text-overflow: ellipsis;
+                        white-space: nowrap;
+                        margin: 0 0 8px 0;
+                      "
+                    >
+                      {{ item.projectName }}
+                    </h4>
                     <p class="memo-meta">
-                      <span>{{ item.relatedTask || '相关任务' }}</span>
-                      <span>{{ item.time }}</span>
+                      <span class="memo-meta-title">
+                        {{ item.title }}
+                      </span>
+                      <span class="memo-meta-date">
+                        <img
+                          style="
+                            width: 14px;
+                            height: 14px;
+                            vertical-align: middle;
+                            margin-right: 4px;
+                          "
+                          src="@/assets/index_images/index-icon4@2x.png"
+                          alt="时间"
+                        />
+                        {{ item.memoDate }}
+                      </span>
+                    </p>
+                    <p class="memo-content-text">
+                      <i class="el-icon-document"></i>
+                      {{ item.content }}
                     </p>
                   </div>
                 </li>
@@ -278,9 +322,10 @@
 
 <script>
   import * as echarts from 'echarts'
-
+  import { memoManageMixin } from '@/views/costAudit/projectInfo/auditProjectManage/memoManage/memoManageMixin'
   export default {
     name: 'Dashboard',
+    mixins: [memoManageMixin],
     data() {
       return {
         province: '山西省',
@@ -351,75 +396,18 @@
             op: '任务详情',
           },
         ],
-        memoList: [
-          {
-            type: 'warning',
-            title: '山西省公立小学教育成本监审',
-            desc: '要求学校提供近三年教学设备采购、师资薪酬等财务明细。',
-            time: '2025-05-06',
-            relatedTask: '山西省公立小学教育成本监审',
-          },
-          {
-            type: 'warning',
-            title: '山西省公立医院医疗服务成本监审',
-            desc: '要依据药品采购、医疗器械使用、医护人员成本等情况提供明细。',
-            time: '2025-05-06',
-            relatedTask: '山西省公立医院医疗服务成本监审',
-          },
-          {
-            type: 'info',
-            title: '太原市生活垃圾处理成本监审',
-            desc: '要求提供垃圾收集、运输、处理各环节的成本支出明细。',
-            time: '2025-05-06',
-            relatedTask: '太原市生活垃圾处理成本监审',
-          },
-          {
-            type: 'info',
-            title: '太原市市政设施维护成本监审',
-            desc: '需要收集道路、桥梁、公共广场等市政设施的维护成本数据。',
-            time: '2025-05-18',
-            relatedTask: '太原市市政设施维护成本监审',
-          },
-          {
-            type: 'warning',
-            title: '山西省公立小学教育成本监审',
-            desc: '要求学校提供近三年教学设备采购、师资薪酬等财务明细。',
-            time: '2025-05-06',
-            relatedTask: '山西省公立小学教育成本监审',
-          },
-        ],
+        memoList: [],
         currentDate: new Date(),
         selectedDate: '',
         showTooltip: false,
       }
     },
     mounted() {
-      this.initChart()
       this.$el.querySelector('div.el-calendar__header').remove()
+      this.initChart()
+      this.initCalendarData()
     },
     methods: {
-      // 获取自定义月份文本
-      getCustomMonthText(date) {
-        const year = date.getFullYear()
-        const month = date.getMonth() + 1
-
-        // 自定义格式
-        return `${year}年${month}月`
-      },
-      handlePrevMonth() {
-        this.currentDate = new Date(
-          this.currentDate.getFullYear(),
-          this.currentDate.getMonth() - 1,
-          this.currentDate.getDate()
-        )
-      },
-      handleNextMonth() {
-        this.currentDate = new Date(
-          this.currentDate.getFullYear(),
-          this.currentDate.getMonth() + 1,
-          this.currentDate.getDate()
-        )
-      },
       // 判断是否为周末
       isWeekend(date) {
         const day = date.getDay() // 0-6,0表示周日,6表示周六
@@ -500,7 +488,8 @@
         })
       },
       loadMoreNews() {
-        this.$message.info('加载更多消息(可对接接口逻辑)')
+        // // 跳转备忘录页面
+        // this.$router.push('/costAudit/projectInfo/memoManage')
       },
       handleOp(type, row) {
         this.$message.info(`执行【${type}】操作:${row.task}`)
@@ -515,124 +504,12 @@
       addMemo() {
         this.$message.info('添加新备忘录')
       },
-      // 获取农历日期
-      getLunarDate(date) {
-        const lunarMap = {
-          '01': '初一',
-          '02': '初二',
-          '03': '初三',
-          '04': '初四',
-          '05': '初五',
-          '06': '初六',
-          '07': '初七',
-          '08': '初八',
-          '09': '初九',
-          10: '初十',
-          11: '十一',
-          12: '十二',
-          13: '十三',
-          14: '十四',
-          15: '十五',
-          16: '十六',
-          17: '十七',
-          18: '十八',
-          19: '十九',
-          20: '二十',
-          21: '廿一',
-          22: '廿二',
-          23: '廿三',
-          24: '廿四',
-          25: '廿五',
-          26: '廿六',
-          27: '廿七',
-          28: '廿八',
-          29: '廿九',
-          30: '三十',
-        }
-
-        const day = date.split('-')[2]
-        return lunarMap[day] || ''
-      },
-      // 获取生肖信息
-      getChineseZodiac(year) {
-        const zodiacs = [
-          '鼠',
-          '牛',
-          '虎',
-          '兔',
-          '龙',
-          '蛇',
-          '马',
-          '羊',
-          '猴',
-          '鸡',
-          '狗',
-          '猪',
-        ]
-        const index = (year - 4) % 12
-        return zodiacs[index]
-      },
-
-      // 获取天干地支
-      getChineseCalendar(year, month) {
-        const heavenlyStems = [
-          '甲',
-          '乙',
-          '丙',
-          '丁',
-          '戊',
-          '己',
-          '庚',
-          '辛',
-          '壬',
-          '癸',
-        ]
-        const earthlyBranches = [
-          '子',
-          '丑',
-          '寅',
-          '卯',
-          '辰',
-          '巳',
-          '午',
-          '未',
-          '申',
-          '酉',
-          '戌',
-          '亥',
-        ]
-
-        // 简化计算,实际需要更复杂的算法
-        const stemIndex = (year - 3) % 10
-        const branchIndex = (year - 3) % 12
-
-        return `${heavenlyStems[stemIndex]}${earthlyBranches[branchIndex]}`
-      },
-
-      // 获取事件描述
-      getEventDescription(date) {
-        const event = this.memoList.find(
-          (item) => item.time === date.substring(5)
-        )
-        return event ? `${event.title} [${event.time}]` : ''
-      },
-
-      // 处理日期点击
-      handleDateClick(data) {
-        this.currentDate = new Date(data.date)
-        this.selectedDate = data.day
-        this.showTooltip = true
-
-        // 2秒后隐藏提示
-        setTimeout(() => {
-          this.showTooltip = false
-        }, 2000)
-      },
     },
   }
 </script>
 
 <style scoped lang="scss">
+  @import '@/views/costAudit/projectInfo/auditProjectManage/memoManage/memoManage.scss';
   .dashboard-page {
     padding: 20px;
   }
@@ -742,52 +619,74 @@
     border-radius: 50%;
   }
   .memo-list {
+    width: 100%;
     list-style: none;
-    padding: 0;
+    padding: 20px;
     margin: 0;
-    /* 移除滚动条限制 */
-    max-height: none;
-    overflow-y: visible;
   }
   .memo-item {
-    padding: 12px 0;
-    border-bottom: 1px solid #f0f0f0;
+    width: 100%;
+    border-radius: 8px;
+    margin-bottom: 20px;
     display: flex;
     align-items: flex-start;
+    transition: all 0.3s ease;
   }
   .memo-item:last-child {
-    border-bottom: none;
-  }
-  .memo-item i {
-    margin-right: 10px;
-    font-size: 18px;
-    margin-top: 2px;
+    margin-bottom: 0;
   }
-  .memo-item i.el-icon-warning {
-    color: #f56c6c;
+  .memo-item .left-icon {
+    display: flex;
+    align-items: flex-start;
+    margin-right: 12px;
+    padding-top: 2px;
+    flex-shrink: 0;
   }
-  .memo-item i.el-icon-info {
-    color: #409eff;
+  .memo-item .left-icon img {
+    width: 15px;
+    height: 15px;
   }
   .memo-content {
+    width: 100%;
     flex: 1;
   }
   .memo-content h4 {
-    margin: 0 0 5px 0;
+    margin: 0 0 8px 0;
+    font-size: 16px;
+    font-weight: bolder;
+    color: #303133;
+  }
+  .memo-meta {
+    width: 95%;
+    // display: flex;
+    // align-items: center;
+    margin-bottom: 8px;
+  }
+  .memo-meta-title {
+    display: inline-block;
+    width: 40%;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
     font-size: 14px;
+    color: #606266;
     font-weight: 500;
   }
-  .memo-desc {
+  .memo-meta-date {
     font-size: 12px;
-    color: #666;
-    margin: 0 0 8px 0;
-    line-height: 1.5;
+    color: #909399;
+    white-space: nowrap;
   }
-  .memo-meta {
-    font-size: 12px;
-    color: #999;
-    display: flex;
-    justify-content: space-between;
+  .memo-content-text {
+    width: 98%;
+    font-size: 14px;
+    color: #606266;
+    line-height: 1.6;
+    margin: 0;
+    padding-left: 0;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
   }
   .left-icon {
     display: flex;
@@ -803,44 +702,6 @@
     color: #333333;
     margin-left: 10px;
   }
-  .month-text {
-    font-size: 16px;
-    font-weight: 500;
-    color: #303133;
-  }
-  .lunar-info {
-    font-size: 14px;
-    margin-left: 10px;
-  }
-
-  .calendar-day:hover {
-    background-color: #f5f7fa;
-  }
-
-  .calendar-day.selected {
-    background-color: #ecf5ff;
-    border-color: #a0d3e8;
-  }
-
-  .calendar-day.has-event {
-    background-color: #f0f9eb;
-  }
-  .calendar-day.weekend .date-number {
-    color: #fd8c2f;
-  }
-
-  .date-number {
-    font-size: 14px;
-    font-weight: 500;
-    color: #303133;
-    margin-bottom: 4px;
-  }
-
-  .lunar-date {
-    font-size: 12px;
-    color: #999;
-    margin-bottom: 4px;
-  }
 
   .event-dot {
     position: absolute;