From 819d40eb1bec7acb2b3adaa4a9a3f8d8eeca1dcc Mon Sep 17 00:00:00 2001
From: zxl <763096477@qq.com>
Date: 星期三, 24 十二月 2025 17:26:06 +0800
Subject: [PATCH] 上报

---
 src/views/workbench.vue     |  384 ++++++++++++++++++++++---
 src/permission.js           |    2 
 src/api/report/report.js    |   39 ++
 src/views/index-nongtou.vue |   14 
 src/utils/date.js           |   57 +++
 src/views/WebViewEntry.vue  |  385 +++++++++++++++++++++++++
 src/router/index.js         |    5 
 7 files changed, 827 insertions(+), 59 deletions(-)

diff --git a/src/api/report/report.js b/src/api/report/report.js
new file mode 100644
index 0000000..cdb5487
--- /dev/null
+++ b/src/api/report/report.js
@@ -0,0 +1,39 @@
+import request from '@/utils/request'
+
+export const reportByDate = (params)=>{
+  return request({
+    url:"/report/listByMonth",
+    method:"GET",
+    params:params
+  })
+
+}
+export const delReport =(params)=>{
+  return request({
+    url:"/report/" +params,
+    method:"delete"
+  })
+}
+
+export const review = (params) =>{
+  return request({
+    url:"/report/review",
+    method:"PUT",
+    params:params
+  })
+}
+export const reportPage = (params)=>{
+  return request({
+    url:"/report/page",
+    method:"GET",
+    params:params
+  })
+
+}
+export const addReport =(data) =>{
+  return request({
+    url:"/report",
+    method:"POST",
+    data:data
+  })
+}
diff --git a/src/permission.js b/src/permission.js
index c568979..5ac6f70 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -8,7 +8,7 @@
 
 NProgress.configure({ showSpinner: false })
 
-const whiteList = ['/login', '/register']
+const whiteList = ['/login', '/register','/web-view-entry']
 
 router.beforeEach((to, from, next) => {
   NProgress.start()
diff --git a/src/router/index.js b/src/router/index.js
index 99fc5a2..14fc845 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -42,6 +42,11 @@
     ]
   },
   {
+    path: '/web-view-entry', // 鍐呭祵鍏ュ彛椤甸潰璺敱
+    component: () => import('@/views//WebViewEntry'),
+    hidden: true // 涓嶆樉绀哄湪渚ц竟鏍忥紝浠呯敤浜� uni-app 鍐呭祵璁块棶
+  },
+  {
     path: '/login',
     component: () => import('@/views/login'),
     hidden: true
diff --git a/src/utils/date.js b/src/utils/date.js
new file mode 100644
index 0000000..bdc9fd4
--- /dev/null
+++ b/src/utils/date.js
@@ -0,0 +1,57 @@
+/**
+ * 杩斿洖骞存湀鏃� 鏃跺垎绉掑瓧绗︿覆 {year}-${month}-${day} ${hour}:${minute}:${second}
+ * @param date
+ * @returns {string}
+ */
+export function  formatDateToFrontend(date) {
+  if (!date) return '';
+  const d = new Date(date);
+  const year = d.getFullYear();
+  const month = (d.getMonth() + 1).toString().padStart(2, '0');
+  const day = d.getDate().toString().padStart(2, '0');
+  const hour = d.getHours().toString().padStart(2, '0');
+  const minute = d.getMinutes().toString().padStart(2, '0');
+  const second = d.getSeconds().toString().padStart(2, '0');
+  return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
+};
+/**
+ * 杩斿洖骞存湀鏃�  {year}骞�${month}鏈�${day}鏃�
+ * @param date
+ * @returns {string}
+ */
+export function formatDate(date) {
+  const year = date.getFullYear();
+  const month = date.getMonth() + 1;
+  const day = date.getDate();
+  return `${year}骞�${month}鏈�${day}鏃;
+};
+/**
+ * 杩斿洖骞存湀鏃� ${year}-${month}-${day}
+ * @param date
+ * @returns {string}
+ */
+export function formatCalendarDate (date) {
+  const year = date.getFullYear();
+  const month = (date.getMonth() + 1).toString().padStart(2, '0');
+  const day = date.getDate().toString().padStart(2, '0');
+  return `${year}-${month}-${day}`;
+};
+
+/**
+ * 浼犲叆鏃堕棿鑾峰緱 鎸囧畾鏃堕棿鎸囧畾鏍煎紡鐨勫紑濮嬪拰缁撴潫鏃ユ湡
+ * @param date
+ * @returns {{startTime: string, endTime: string}}
+ */
+export function getDayStartAndEnd(date){
+  const start = new Date(date);
+  start.setDate(1); // 鏃ユ湡缃负褰撴湀1鍙�
+  start.setHours(0, 0, 0); // 缃负0鐐�0鍒�0绉�
+
+  let startTime = formatDateToFrontend(start);
+  const end = new Date(date);
+  end.setMonth(end.getMonth() + 1); // 鍒囨崲鍒颁笅涓�涓湀
+  end.setDate(0); // 鏃ユ湡缃负0锛岃嚜鍔ㄥ洖閫�鍒颁笂鏈堟渶鍚庝竴澶�
+  end.setHours(23, 59, 59); // 缃负23鐐�59鍒�59绉�
+  let endTime = formatDateToFrontend(end);
+  return {startTime,endTime};
+}
diff --git a/src/views/WebViewEntry.vue b/src/views/WebViewEntry.vue
new file mode 100644
index 0000000..113a30c
--- /dev/null
+++ b/src/views/WebViewEntry.vue
@@ -0,0 +1,385 @@
+<template>
+  <div class="app-container">
+    <el-card class="box-card" >
+      <div slot="header" class="clearfix" style="display: flex">
+        <div style="flex: 1" class="el-icon-document">{{`浠诲姟璇︽儏锛歚 + this.processName}}</div>
+        <div style="flex: 2; color: #303133">{{projectName + '鈥斺��' + flowName}}</div>
+        <el-button style="float: right;" size="mini" type="danger" @click="goBack">鍏抽棴</el-button>
+      </div>
+      <el-tabs  tab-position="top" v-model="activeName" @tab-click="handleClick">
+        <!--琛ㄥ崟淇℃伅-->
+        <el-tab-pane label="琛ㄥ崟淇℃伅" name="1">
+          <!--鍒濆鍖栨祦绋嬪姞杞借〃鍗曚俊鎭�-->
+          <el-col :span="24" v-loading="formLoading" class="tab-min-height">
+            <div v-if="formDataList && formDataList.length > 0">
+              <div v-for="(formDataObj, index) in formDataList" :key="index" class="form-warp" style="position: relative">
+                <el-row>
+                  <el-col :span="18">
+                    <div v-if="formDataObj.current">
+                      <div class="current">褰撳墠闃舵锛�<span>{{formDataObj.beforeNodeName}}</span></div>
+                    </div>
+                    <div v-else-if="formDataList.length > 1">
+                      <div class="before">鍓嶇疆闃舵锛�<span>{{formDataObj.beforeNodeName}}</span></div>
+                    </div>
+                    <div v-if="formDataObj != null && formDataObj.formJsonObj != null">
+                      <v-form-render  :form-data="formDataObj.formJsonObj.formJson" :ref="'form' + index"/>
+                    </div>
+                    <div v-else>
+                      <el-alert
+                        title="鏈粦瀹氳〃鍗�"
+                        type="warning"
+                        :closable="false"
+                      >
+                      </el-alert>
+                    </div>
+                    <div v-if="formDataList.length <= 1">
+                      <div class="before_none">鍓嶇疆闃舵锛�<span>涓嶅瓨鍦ㄥ墠缃樁娈�</span></div>
+                      <el-alert
+                        title="涓嶅瓨鍦ㄥ墠缃樁娈�"
+                        type="warning"
+                        :closable="false"
+                      >
+                      </el-alert>
+                    </div>
+                  </el-col>
+                  <el-col :span="6">
+                    <log-time-line v-if="formDataObj.events.length > 0" :log-list="formDataObj.events"/>
+                  </el-col>
+                </el-row>
+              </div>
+            </div>
+          </el-col>
+        </el-tab-pane>
+        <!--娴佺▼娴佽浆璁板綍-->
+        <el-tab-pane label="娴佽浆璁板綍" name="2">
+          <el-col :span="16" :offset="4" >
+            <div class="block">
+              <el-timeline>
+                <el-timeline-item
+                  v-for="(item,index ) in flowRecordList"
+                  :key="index"
+                  :icon="setIcon(item.finishTime)"
+                  :color="setColor(item.finishTime)"
+                >
+                  <p style="font-weight: 700">{{item.taskName}}
+                    <span v-if="item.comment && item.comment.type === '3'" style="color: red">(鎵ц浜嗛┏鍥�)</span>
+                    <span v-if="item.overtime && item.overtime==='red'" style="color: red">(宸茶秴鏃�)</span>
+                    <span v-if="item.overtime && item.overtime==='yellow'" style="color: orange">(鍗冲皢瓒呮椂)</span>
+                  </p>
+                  <el-card :body-style="{ padding: '10px' }">
+                    <el-descriptions class="margin-top" :column="1" size="small" border>
+                      <el-descriptions-item v-if="item.assigneeName" label-class-name="my-label">
+                        <template slot="label"><i class="el-icon-user"></i>鍔炵悊浜�</template>
+                        {{item.assigneeName}}
+                        <el-tag type="info" size="mini">{{item.deptName}}</el-tag>
+                      </el-descriptions-item>
+                      <el-descriptions-item v-if="item.candidate" label-class-name="my-label">
+                        <template slot="label"><i class="el-icon-user"></i>鍊欓�夊姙鐞�</template>
+                        {{item.candidate}}
+                      </el-descriptions-item>
+                      <el-descriptions-item label-class-name="my-label">
+                        <template slot="label"><i class="el-icon-date"></i>鎺ユ敹鏃堕棿</template>
+                        {{item.createTime}}
+                      </el-descriptions-item>
+                      <el-descriptions-item v-if="item.finishTime" label-class-name="my-label">
+                        <template slot="label"><i class="el-icon-date"></i>澶勭悊鏃堕棿</template>
+                        {{item.finishTime}}
+                      </el-descriptions-item>
+                      <el-descriptions-item v-if="item.duration"  label-class-name="my-label">
+                        <template slot="label"><i class="el-icon-time"></i>鑰楁椂</template>
+                        {{item.duration}}
+                      </el-descriptions-item>
+                      <el-descriptions-item v-if="item.comment" label-class-name="my-label">
+                        <template slot="label"><i class="el-icon-tickets"></i>澶勭悊鎰忚</template>
+                        {{item.comment.comment}}
+                      </el-descriptions-item>
+                    </el-descriptions>
+                  </el-card>
+                </el-timeline-item>
+              </el-timeline>
+            </div>
+          </el-col>
+        </el-tab-pane>
+        <!--娴佺▼鍥�-->
+<!--        <el-tab-pane label="娴佺▼鍥�" name="3">-->
+<!--          <div class="tab-min-height" v-loading="imgLoading">-->
+<!--            <bpmn-viewer :flowData="flowData" :procInsId="taskForm.procInsId"/>-->
+<!--          </div>-->
+<!--        </el-tab-pane>-->
+      </el-tabs>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import {flowRecord} from "@/api/flowable/finished";
+import {getProcessVariables, flowXmlAndNode} from "@/api/flowable/definition";
+import {flowTaskForm, flowTaskFormDetail} from "@/api/flowable/todo";
+import BpmnViewer from '@/components/Process/viewer';
+import LogView from "@/views/projectProcess/components/LogView";
+import LogTimeLine from "@/views/projectProcess/components/LogTimeLine";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import {setToken} from "@/utils/auth";
+
+export default {
+  name: "Record",
+  components: {
+    BpmnViewer, LogView, LogTimeLine
+  },
+  props: {},
+  data() {
+    return {
+      formLoading: false, // 鍔犺浇琛ㄥ崟
+      imgLoading: false, // 鍔犺浇娴佺▼鍥�
+      projectName: '',
+      flowName: '',
+      processName:'',
+      // 妯″瀷xml鏁版嵁
+      flowData: {},
+      formDataList: [],  // 琛ㄥ崟鍒楄〃
+      activeName: '1',
+      // 鏌ヨ鍙傛暟
+      queryParams: {},
+      // 閬僵灞�
+      loading: true,
+      flowRecordList: [], // 娴佺▼娴佽浆鏁版嵁
+      goBackParams: {},
+      taskForm:{
+        multiple: false,
+        comment:"", // 鎰忚鍐呭
+        procInsId: "", // 娴佺▼瀹炰緥缂栧彿
+        instanceId: "", // 娴佺▼瀹炰緥缂栧彿
+        deployId: "",  // 娴佺▼瀹氫箟缂栧彿
+        taskId: "" ,// 娴佺▼浠诲姟缂栧彿
+        procDefId: "",  // 娴佺▼缂栧彿
+      },
+
+    };
+  },
+  created() {
+    this.initPage()
+
+
+    // 娴佺▼浠诲姟閲嶈幏鍙栧彉閲忚〃鍗�
+    this.processVariables( this.taskForm.taskId, this.taskForm.procInsId)
+    this.getFlowRecordList(this.taskForm.procInsId);
+  },
+  methods: {
+    /**
+     * 椤甸潰鍒濆鍖栨牳蹇冮�昏緫
+     */
+    async initPage() {
+      try {
+        this.loading = true
+        this.hasError = false
+
+        // 1. 鎻愬彇 URL 涓殑 Token
+        const urlToken = this.getUrlParam('token')
+        if (!urlToken) {
+          throw new Error('鏈幏鍙栧埌鏈夋晥 Token')
+        }
+
+        // 2. 瑙g爜 Token
+        const token = decodeURIComponent(urlToken)
+
+        // 3. 瀛樺偍 Token 鍒� Cookie
+        setToken(token)
+
+        // 4. 瀛樺偍 Token 鍒� Vuex
+        this.$store.commit('SET_TOKEN', token)
+
+        // 鎻愬彇鍊�
+        this.taskForm.deployId = decodeURIComponent(this.getUrlParam('deployId'));
+        this.taskForm.taskId =  decodeURIComponent(this.getUrlParam('taskId'))
+        this.taskForm.procInsId =  decodeURIComponent(this.getUrlParam('procInsId'));
+        this.projectName =   decodeURIComponent(this.getUrlParam('projectName'));
+        this.flowName =  decodeURIComponent(this.getUrlParam('flowName'));
+        this.processName =  decodeURIComponent(this.getUrlParam('processName'));
+
+        //瑙g爜
+
+
+      } catch (err) {
+        this.hasError = true
+        this.errorMsg = err.message || '鍒濆鍖栧け璐ワ紝璇烽噸璇�'
+        console.error('椤甸潰鍒濆鍖栧け璐ワ細', err)
+      } finally {
+        this.loading = false
+      }
+    },
+
+    /**
+     * 鎻愬彇 URL 鏌ヨ鍙傛暟
+     */
+    getUrlParam(name) {
+      const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`)
+      const r = window.location.search.substr(1).match(reg)
+      if (r != null) {
+        return r[2]
+      }
+      return ''
+    },
+    handleClick(tab, event) {
+      if (tab.name === '3') {
+        this.imgLoading = true
+        flowXmlAndNode({processInsId: this.taskForm.procInsId, deployId: this.taskForm.deployId}).then(res => {
+          this.imgLoading = false
+          this.flowData = res.data;
+        })
+      }
+    },
+    setIcon(val) {
+      if (val) {
+        return "el-icon-check";
+      } else {
+        return "el-icon-time";
+      }
+    },
+    setColor(val) {
+      if (val) {
+        return "#2bc418";
+      } else {
+        return "#b3bdbb";
+      }
+    },
+    /** 娴佺▼娴佽浆璁板綍 */
+    getFlowRecordList(procInsId) {
+      const that = this
+      const params = {procInsId: procInsId}
+      flowRecord(params).then(res => {
+        that.flowRecordList = res.data.flowList;
+      }).catch(res => {
+        this.goBack();
+      })
+    },
+    /** 鑾峰彇娴佺▼鍙橀噺鍐呭 */
+    processVariables(taskId, processInsId) {
+      if (taskId) {
+        this.formLoading = true
+        // 鎻愪氦娴佺▼鐢宠鏃跺~鍐欑殑琛ㄥ崟瀛樺叆浜嗘祦绋嬪彉閲忎腑鍚庣画浠诲姟澶勭悊鏃堕渶瑕佸睍绀�
+        flowTaskFormDetail(processInsId, taskId).then(res => {
+          this.formDataList = res.data
+          if (this.formDataList && this.formDataList.length > 0) {
+            this.$nextTick(() => {
+              this.formDataList.forEach((formDataObj, index) => {
+                console.log("琛ㄥ崟鏁版嵁鍒楄〃", formDataObj.formJson)
+                let that = this
+                if (formDataObj.formJsonObj) {
+                  eval("that.$refs.form" + index)[0].setFormJson(formDataObj.formJsonObj.formJson);
+
+                  eval("that.$refs.form" + index)[0].setFormData(formDataObj.formJsonObj);
+                  this.$nextTick(() => {
+                    eval("that.$refs.form" + index)[0].disableForm();
+                  })
+                }
+              })
+            })
+          }
+          this.formLoading = false
+
+        });
+      }
+    },
+    /** 杩斿洖椤甸潰 */
+    goBack() {
+      // // 鍏抽棴褰撳墠鏍囩椤�
+      // this.$store.dispatch("tagsView/delView", this.$route);
+      // this.$router.push({
+      //   path: '/projectFlow/detail',
+      //   query: {
+      //     projectId: this.goBackParams.projectId,
+      //     processDefId: this.goBackParams.processDefId,
+      //     processName: this.goBackParams.processName
+      //   }
+      // })
+    },
+  }
+};
+</script>
+<style lang="scss" scoped>
+.test-form {
+  margin: 15px auto;
+  width: 800px;
+  padding: 15px;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both
+}
+
+.box-card {
+  width: 100%;
+  margin-bottom: 20px;
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.my-label {
+  background: #E1F3D8;
+}
+
+.form-warp {
+  min-width: 700px;
+  padding: 20px;
+  margin-top: 5px;
+  margin-bottom: 20px;
+  margin-left: 3px;
+  margin-right: 3px;
+  box-shadow: rgba(67, 71, 85, 0.27) 0px 0px 0.1em, rgba(90, 125, 188, 0.05) 0px 0.1em 0.5em;
+}
+
+.before {
+  span {
+    color: #F56C6C
+  }
+
+  margin-bottom: 15px;
+  color: #E6A23C
+}
+
+.before_none {
+  span {
+    color: #F56C6C
+  }
+
+  margin-bottom: 15px;
+  margin-top: 15px;
+  color: #E6A23C
+}
+
+.reject-but {
+  position: absolute;
+  top: 4px;
+  right: 4px
+}
+
+.current {
+  span {
+    color: #409EFF
+  }
+
+  margin-bottom: 15px;
+  color: #E6A23C
+}
+
+.op-list {
+  position: absolute;
+  top: 4px;
+  right: 4px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.tab-min-height {
+  min-height: 500px;
+}
+</style>
diff --git a/src/views/index-nongtou.vue b/src/views/index-nongtou.vue
index 31aeb41..c820b71 100644
--- a/src/views/index-nongtou.vue
+++ b/src/views/index-nongtou.vue
@@ -876,18 +876,18 @@
       return map[status] || '';
     },
     handleTaskDetail(task) {
-    console.log(task)
       const queryParams= {
-        taskName: '',
+        taskName: task.taskName,
         taskType: 'todo',
         pageSize: 5,
         currentPage: 1,
-        projectId: null,
-        processDefId: null,
-        processInsId: null,
-        deployId: null,
-        processName: '' // 娴佺▼鍚嶇О
+        projectId: task.checkPointInfo.id +"",
+        processDefId: task.checkPointInfo.processDefinitionId,
+        processInsId: task.checkPointInfo.processInstanceId,
+        deployId: task.checkPointInfo.deployId,
+        processName: task.checkPointInfo.processName // 娴佺▼鍚嶇О
       }
+
       this.$router.push({ path: '/flowable/task/myProcess/detail/index',
         query: {
           projectName: task.checkPointInfo.projectName,
diff --git a/src/views/workbench.vue b/src/views/workbench.vue
index 1d02a08..cd36e6f 100644
--- a/src/views/workbench.vue
+++ b/src/views/workbench.vue
@@ -19,6 +19,15 @@
           <span class="stat-number">{{ totalActiveTasks }}</span>
           <span class="stat-label">浠婃棩澶勭悊</span>
         </div>
+        <div style="display: flex;align-items: center">
+          <el-button size="mini" @click="handleAddReport()"
+                     class="report-btn"
+                     icon="el-icon-upload2">涓婃姤</el-button>
+          <el-button size="mini" @click="handleViewReport()"
+                     class="report-btn"
+                     icon="el-icon-view">鏌ョ湅涓婃姤</el-button>
+        </div>
+
       </div>
       <div class="user-profile">
 <!--        <el-dropdown>-->
@@ -123,6 +132,17 @@
                 </template>
               </el-table-column>
             </el-table>
+          </div>
+
+          <div class="pagination-container">
+            <el-pagination
+              @current-change="handleCurrentChange"
+              :current-page="waitTaskQuery.currentPage"
+              :page-size="waitTaskQuery.pageSize"
+              layout="total, sizes, prev, pager, next, jumper"
+              :total="waitTaskTotal"
+            >
+            </el-pagination>
           </div>
 
         </div>
@@ -233,16 +253,7 @@
               </el-table-column>
             </el-table>
           </div>
-          <div class="pagination-container">
-            <el-pagination
-              @current-change="handleCurrentChange"
-              :current-page="waitTaskQuery.currentPage"
-              :page-size="waitTaskQuery.pageSize"
-              layout="total, sizes, prev, pager, next, jumper"
-              :total="waitTaskTotal"
-            >
-            </el-pagination>
-          </div>
+
         </div>
       </div>
     </div>
@@ -300,6 +311,107 @@
         <el-button type="primary" @click="submitSaveSchedule">纭畾</el-button>
       </template>
     </el-dialog>
+    <el-dialog
+      :title="reportTitle"
+      :visible.sync="reportDialogVisible"
+      width="600px"
+      @close="resetReportForm"
+    >
+      <el-form
+        ref="reportFormRef"
+        :model="reportForm"
+        :rules="reportRules"
+        label-width="90px"
+      >
+        <el-form-item label="閫夋嫨椤圭洰" prop="projectId">
+          <el-select
+            v-model="reportForm.projectId"
+            clearable
+            placeholder="閫夋嫨椤圭洰"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="project in allProjects"
+              :key="project.id"
+              :label="project.name"
+              :value="project.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="涓婃姤鍐呭" prop="content">
+          <el-input
+            v-model="reportForm.content"
+            type="textarea"
+            placeholder="璇疯緭鍏ヤ笂鎶ュ唴瀹�"
+            rows="4"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="涓婁紶闄勪欢">
+          <FileUpload v-model="reportForm.fileUrl" :isShowTip="true" />
+        </el-form-item>
+      </el-form>
+      <template v-slot:footer>
+        <el-button @click="reportDialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary" @click="submitReport">纭畾</el-button>
+      </template>
+    </el-dialog>
+    <el-dialog
+      title="涓婃姤璁板綍"
+      :visible.sync="reportListDialogVisible"
+      width="700px"
+    >
+      <div class="calendar-section">
+        <el-calendar v-model="reportCalendarDate">
+          <template
+            slot="dateCell"
+            slot-scope="{date, data}">
+            <div class="calendar-day">
+              {{ data.day.split('-').slice(2).join('-') }}
+              <div v-if="getReportCount(date) > 0" class="schedule-count">
+                {{ getReportCount(date) }}涓笂鎶�
+              </div>
+            </div>
+          </template>
+        </el-calendar>
+      </div>
+      <div class="schedule-list-section">
+        <div class="section-header">
+          <h3>涓婃姤鍒楄〃</h3>
+          <div>
+            <el-button type="text" icon="el-icon-refresh" @click="getReportList" :disabled="reportRefreshing">鍒锋柊</el-button>
+          </div>
+        </div>
+        <div class="schedule-list">
+          <el-table
+            v-loading="reportLoading"
+            :data="filteredReport"
+            style="width: 100%"
+            height="250">
+            <el-table-column
+              prop="time"
+              label="鏃堕棿"
+             >
+            </el-table-column>
+            <el-table-column
+              prop="title"
+              label="浜嬮」"
+             >
+            </el-table-column>
+            <el-table-column
+              label="鎿嶄綔">
+              <template slot-scope="scope">
+                <el-button size="mini" @click="handleEditReport(scope.row)">鏌ョ湅</el-button>
+                <el-button size="mini" @click="handleReturn(scope.row)" :disabled="scope.row.status !== 'PendingReview'">鎾ゅ洖</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+
+      </div>
+      <template v-slot:footer>
+        <el-button @click="reportListDialogVisible = false">鍏� 闂�</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -315,17 +427,27 @@
   del,
   countTodayTask,
 } from "@/api/workbench/workbench"
+
 import {getTaskIsAuditing} from "@/api/projectProcess/projectProcess";
 import {getProjectSelectList} from "@/api/index";
+import {addReport, reportByDate,delReport} from "@/api/report/report";
+import { formatDateToFrontend,formatDate,formatCalendarDate,getDayStartAndEnd } from "@/utils/date.js"
 export default {
 
   data() {
     return {
-
-
       diaLogTitle:"",
+      reportTitle:"",
       allProjects:[],
+
       scheduleDialogVisible: false,
+      reportLoading:false,
+
+      reportCurrentPageNum:1,
+      reportPageSize:5,
+      reportTotal:5,
+      reportDialogVisible: false,
+      reportListDialogVisible: false,
       // 鏂板锛氭柊澧炴棩绋嬭〃鍗曟暟鎹紙瀵瑰簲WorkStationSchedule瀹炰綋锛�
       scheduleForm: {
         id:'',
@@ -333,6 +455,12 @@
         completedTime: '',
         projectId:''
 
+      },
+      reportForm: {
+        id:'',
+        projectId: '',
+        content: '',
+        fileUrl: []
       },
       // 鏂板锛氳〃鍗曟牎楠岃鍒�
       scheduleRules: {
@@ -347,6 +475,15 @@
           {required:true,message: '璇烽�夋嫨椤圭洰', trigger: 'change'}
         ]
       },
+      reportRules: {
+        projectId: [
+          { required: true, message: '璇烽�夋嫨椤圭洰', trigger: 'change' }
+        ],
+        content: [
+          { required: true, message: '璇疯緭鍏ヤ笂鎶ュ唴瀹�', trigger: 'blur' },
+          { max: 500, message: '涓婃姤鍐呭鏈�澶�500涓瓧绗�', trigger: 'blur' }
+        ]
+      },
       queryParams: {
         taskName: '',
         taskType: 'todo',
@@ -359,6 +496,7 @@
         processName: '' // 娴佺▼鍚嶇О
       },
       waitTaskRefreshing:false,
+      reportRefreshing:false,
       scheduleRefreshing:false,
       auditHistoryRefreshing:false,
       loading:false,
@@ -381,20 +519,14 @@
         avatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
         department: '椤圭洰閮�'
       },
-      currentDate: this.formatDate(new Date()),
+      currentDate: formatDate(new Date()),
       todayTasks: 0,
       todaySchedules: 0,
       totalActiveTasks: 0,
       activeProject: 'all',
       projects: [],
       tasks: [],
-      logs: [
-        { id: 1, time: '09:30', project: '灏勬椽甯傚浗瀹跺偍澶囨灄寤鸿椤圭洰锛堜竴鏈燂級', action: '鎻愪氦', detail: '鎻愪氦浜嗘柦宸ュ浘绾稿鏍哥敵璇�' },
-        { id: 2, time: '10:15', project: '灏勬椽甯傜櫧缇借倝楦′骇涓氬缓璁鹃」鐩�', action: '鏇存柊', detail: '鏇存柊浜嗘潗鏂欓噰璐竻鍗�' },
-        { id: 3, time: '11:00', project: '閬傚畞甯傚皠娲�2024鈥�2027骞村害涓滃寳鐗囧尯楂樻爣鍑嗗啘鐢板缓璁鹃」鐩�', action: '瀹屾垚', detail: '瀹屾垚浜嗙數鍔涜澶囨祴璇�' },
-        { id: 4, time: '14:30', project: '灏勬椽甯傜幇浠g涓氱ず鑼冨熀鍦板缓璁鹃」鐩�', action: '鍒涘缓', detail: '鍒涘缓浜嗘柊鐨勫畨瑁呰鍒�' },
-        { id: 5, time: '16:45', project: '灏勬椽甯傛脖鐗岄晣缁煎悎姘村埄璁炬柦寤鸿椤圭洰', action: '瀹℃壒', detail: '瀹℃壒閫氳繃浜嗗畨鍏ㄦ柟妗�' }
-      ],
+      logs: [],//鏃ュ織鏁版嵁瀵硅薄
       achievements: {
         completedTasks: 0,
         avgDuration: 0,
@@ -402,13 +534,50 @@
         completedSchedules: 0
       },
       calendarDate: new Date(),
-      schedules: []
+      lastCalendarDate:new Date(),
+      reportCalendarDate: new Date(),
+      lastReportCalendarDate: new Date(),
+      schedules: [],
+      reports:[]
     }
   },
+  watch:{
+    calendarDate(newDate, oldDate) {
+      // 鎺掗櫎銆岀偣鍑绘棩鏈熷崟鍏冩牸銆嶅鑷寸殑鍙樺寲锛堜粎鏃ユ湡鍙橈紝鏈堜唤/骞翠唤涓嶅彉锛�
+      const isOnlyDayChange =
+        newDate.getFullYear() === oldDate.getFullYear() &&
+        newDate.getMonth() === oldDate.getMonth() &&
+        newDate.getDate() !== oldDate.getDate();
+
+      if (!isOnlyDayChange) {
+        // 瑙﹀彂鎸夐挳鐐瑰嚮閫昏緫锛堜笂鏈�/涓嬫湀/浠婃棩锛�
+        this.getScheduleList();
+        this.lastCalendarDate = new Date(newDate); // 鏇存柊璁板綍鐨勬棩鏈�
+      }
+    },
+    reportCalendarDate(newDate, oldDate) {
+      // 鎺掗櫎銆岀偣鍑绘棩鏈熷崟鍏冩牸銆嶅鑷寸殑鍙樺寲锛堜粎鏃ユ湡鍙橈紝鏈堜唤/骞翠唤涓嶅彉锛�
+      const isOnlyDayChange =
+        newDate.getFullYear() === oldDate.getFullYear() &&
+        newDate.getMonth() === oldDate.getMonth() &&
+        newDate.getDate() !== oldDate.getDate();
+
+      if (!isOnlyDayChange) {
+        // 瑙﹀彂鎸夐挳鐐瑰嚮閫昏緫锛堜笂鏈�/涓嬫湀/浠婃棩锛�
+        this.getReportList();
+        this.lastReportCalendarDate = new Date(newDate); // 鏇存柊璁板綍鐨勬棩鏈�
+      }
+    },
+  },
   computed: {
+    // 璁$畻鑾峰緱鎸囧畾鏃ユ湡鏁版嵁
     filteredSchedules() {
-      const selectedDate = this.formatCalendarDate(this.calendarDate);
+      const selectedDate = formatCalendarDate(this.calendarDate);
       return this.schedules.filter(schedule => schedule.date === selectedDate);
+    },
+    filteredReport(){
+      const selectDate = formatCalendarDate(this.reportCalendarDate);
+      return this.reports.filter(report => report.date === selectDate);
     }
   },
   mounted() {
@@ -419,6 +588,33 @@
     this.getAuditHistoryPage();
   },
   methods: {
+    handleReturn(row){
+      delReport(row.id).then(res =>{
+        if (res.code === 200){
+          this.getReportList()
+        }
+      })
+    },
+    handleAddReport(){
+      this.reportTitle="鎻愪氦涓婃姤";
+      this.resetReportForm();
+      this.reportDialogVisible = true;
+    },
+    handleEditReport(row){
+      this.reportTitle="缂栬緫涓婃姤";
+      this.resetReportForm();
+      this.reportDialogVisible = true;
+
+      this.reportForm.id = row.id;
+      this.reportForm.projectId = row.projectId + ""; //鍏堣浆涓哄瓧绗︿覆绫诲瀷 鎻愪氦鐨勬椂鍊欒浆涓烘暟瀛�
+      this.reportForm.content = row.title;
+      this.reportForm.fileUrl = row.fileUrl;
+    },
+
+    handleViewReport(){
+      this.getReportList();
+      this.reportListDialogVisible = true;
+    },
     getAuditTypeText(auditType) {
       // 鏄犲皠鍏崇郴锛氬悗绔�� 鈫� 鍓嶇姹夊瓧
       const typeMap = {
@@ -439,6 +635,7 @@
         }
       })
     },
+    // 鑾峰緱涓嬫媺椤圭洰鏁版嵁
     initSelect(){
       getProjectSelectList().then(res =>{
         if (res.code === 200){
@@ -449,12 +646,34 @@
         }
       })
     },
+    // 鑾峰緱涓婃姤鍒楄〃鏁版嵁
+    getReportList(){
+      if (this.reportRefreshing){
+        return
+      }
+      const form ={
+        startTime: getDayStartAndEnd(this.reportCalendarDate).startTime,
+        endTime: getDayStartAndEnd(this.reportCalendarDate).endTime,
+        projectId:this.activeProject
+      }
+      this.reportLoading = true;
+      this.reportRefreshing = true;
+      // 鍚庣鎺ュ彛鑾峰緱鏁版嵁
+      reportByDate(form).then(res =>{
+        this.reportRefreshing = false;
+        this.reportLoading = false;
+        if (res.code === 200){
+          this.reports = res.data;
+        }
+      })
+    },
+    // 鑾峰緱鏃ョ▼鍒楄〃鏁版嵁
     getScheduleList(){
       if (this.scheduleRefreshing){
         return
       }
       const form ={
-        completedTime:this.formatDateToFrontend(this.calendarDate),
+        completedTime:formatDateToFrontend(this.calendarDate),
         projectId:this.activeProject
       }
       this.scheduleLoading = true
@@ -467,17 +686,7 @@
         }
       })
     },
-    formatDateToFrontend(date) {
-      if (!date) return '';
-      const d = new Date(date);
-      const year = d.getFullYear();
-      const month = (d.getMonth() + 1).toString().padStart(2, '0');
-      const day = d.getDate().toString().padStart(2, '0');
-      const hour = d.getHours().toString().padStart(2, '0');
-      const minute = d.getMinutes().toString().padStart(2, '0');
-      const second = d.getSeconds().toString().padStart(2, '0');
-      return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
-    },
+
     async submitSaveSchedule(){
       this.$refs.scheduleFormRef.validate((valid, fields) => {
         if (valid) {
@@ -485,7 +694,7 @@
           if (this.scheduleForm.id === null || this.scheduleForm.id ==='' || this.scheduleForm.id === undefined){
             const submitData = {
               content: this.scheduleForm.content,
-              completedTime: this.formatDateToFrontend(this.scheduleForm.completedTime),
+              completedTime: formatDateToFrontend(this.scheduleForm.completedTime),
               projectId:this.scheduleForm.projectId
             };
             this.$message.success('琛ㄥ崟鎻愪氦鎴愬姛锛�');
@@ -501,7 +710,7 @@
             const submitData = {
               id:this.scheduleForm.id,
               content: this.scheduleForm.content,
-              completedTime: this.formatDateToFrontend(this.scheduleForm.completedTime),
+              completedTime: formatDateToFrontend(this.scheduleForm.completedTime),
               projectId:this.scheduleForm.projectId
             };
             this.$message.success('琛ㄥ崟鎻愪氦鎴愬姛锛�');
@@ -551,6 +760,46 @@
         this.$refs.scheduleFormRef.resetFields();
       }
     },
+    resetReportForm() {
+      this.reportForm = {
+        projectId: '',
+        content: '',
+        fileUrl: []
+      };
+      if (this.$refs.reportFormRef) {
+        this.$refs.reportFormRef.resetFields();
+      }
+    },
+    submitReport() {
+
+      this.$refs.reportFormRef.validate(valid => {
+        if (valid) {
+          const matchItem = this.allProjects.find(item => item.id === this.reportForm.projectId);
+          let files=[];
+
+          this.reportForm.fileUrl.forEach(item =>{
+            if (item.url !== null || itme.url !== '')
+            files.push(item.url)
+          })
+          const submitData = {
+            projectId: Number(this.reportForm.projectId),
+            content: this.reportForm.content,
+            projectName:matchItem.name,
+            fileUrl: files
+          };
+
+          this.$message.success('涓婃姤鍐呭宸插噯澶囧氨缁�');
+          this.reportDialogVisible = false;
+          addReport(submitData).then(res =>{
+            if (res.code === 200){
+              this.getReportList();
+            }
+          })
+        } else {
+          this.$message.error('璇峰畬鍠勪笂鎶ヤ俊鎭�');
+        }
+      });
+    },
     addProject(){
       this.$router.push({path: '/projectEngineering/project/ProjectDetails'});
     },
@@ -597,8 +846,8 @@
         this.loading = false;
         this.waitTaskRefreshing = false;
         if (res.code === 200){
-          this.tasks = res.data.data;
-          this.waitTaskTotal = res.data.total;
+          this.tasks = res.data;
+          this.waitTaskTotal = res.total;
         }
 
       })
@@ -656,18 +905,6 @@
     isProjectNameTooLong(name) {
       return name.length > 10;
     },
-    formatDate(date) {
-      const year = date.getFullYear();
-      const month = date.getMonth() + 1;
-      const day = date.getDate();
-      return `${year}骞�${month}鏈�${day}鏃;
-    },
-    formatCalendarDate(date) {
-      const year = date.getFullYear();
-      const month = (date.getMonth() + 1).toString().padStart(2, '0');
-      const day = date.getDate().toString().padStart(2, '0');
-      return `${year}-${month}-${day}`;
-    },
     handleProjectSelect(index) {
       this.activeProject = index;
       console.log(this.activeProject)
@@ -684,6 +921,14 @@
     },
     handleTaskEdit(row) {
       console.log(row)
+      this.queryParams.projectId = row.checkPointInfo.id +"";
+      this.queryParams.processDefId = row.checkPointInfo.processDefinitionId;
+      this.queryParams.processInsId = row.checkPointInfo.processInstanceId;
+      this.queryParams.deployId = row.checkPointInfo.deployId;
+      this.queryParams.processName = row.checkPointInfo.processName;
+
+      console.log(this.queryParams)
+
       if (row.taskType === '瀹圭己') {
         this.$router.push({
           path: '/flowable/task/myProcess/send/index',
@@ -728,8 +973,15 @@
         })
       }
     },
+    // 鑾峰緱璁℃暟
+    getReportCount(date){
+      const dateStr = formatCalendarDate(date);
+      return this.reports.filter(s => s.date === dateStr).length;
+
+    },
+
     getScheduleCount(date) {
-      const dateStr = this.formatCalendarDate(date);
+      const dateStr = formatCalendarDate(date);
       return this.schedules.filter(s => s.date === dateStr).length;
     },
     handleDeleteSchedule(schedule) {
@@ -1009,4 +1261,34 @@
   padding: 0 !important;
   border: none !important;
 }
+.report-btn {
+  background: linear-gradient(135deg, #409eff, #1e88e5) !important;
+  border: none !important;
+  border-radius: 20px !important;
+  padding: 6px 16px !important;
+  color: white !important;
+  font-weight: 500 !important;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3) !important;
+  transition: all 0.3s ease !important;
+  height: 32px !important;
+  margin-left: 10px;
+}
+.report-btn:hover {
+  background: linear-gradient(135deg, #66b1ff, #409eff) !important;
+  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4) !important;
+  transform: translateY(-1px);
+}
+
+.report-btn:active {
+  background: linear-gradient(135deg, #1e88e5, #0d6efd) !important;
+  box-shadow: 0 2px 6px rgba(64, 158, 255, 0.2) !important;
+  transform: translateY(0);
+}
+
+.report-btn:disabled {
+  background: #e0e0e0 !important;
+  color: #999 !important;
+  box-shadow: none !important;
+  transform: none !important;
+}
 </style>

--
Gitblit v1.8.0