Parcourir la source

Merge remote-tracking branch 'origin/master'

Guo1B0 il y a 10 mois
Parent
commit
c9285326aa

+ 14 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserController.java

@@ -882,6 +882,13 @@ public class UserController {
         return httpRespMsg;
     }
 
+    /**
+    * @Description:ldap获取组织架构
+    * @Param: []
+    * @return: com.management.platform.util.HttpRespMsg
+    * @Author: yurk
+    * @Date: 2024/7/19
+    */
     @RequestMapping("/getOU")
     public HttpRespMsg getOU() throws NamingException {
         HttpRespMsg httpRespMsg=new HttpRespMsg();
@@ -889,6 +896,13 @@ public class UserController {
         return httpRespMsg;
     }
 
+    /**
+    * @Description:ldap获取人员
+    * @Param: []
+    * @return: com.management.platform.util.HttpRespMsg
+    * @Author: yurk
+    * @Date: 2024/7/19
+    */
     @RequestMapping("/getUser")
     public HttpRespMsg getUser() throws Exception {
         HttpRespMsg httpRespMsg=new HttpRespMsg();

+ 8 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -770,8 +770,15 @@ public class TimingTask {
         }
     }
 
+    /**
+    * @Description:定时任务同步ladp组织架构数据
+    * @Param: []
+    * @return: void
+    * @Author: yurk
+    * @Date: 2024/7/19
+    */
     @Scheduled(cron = "0 10 1 ? * *")
-    private void synAd() throws Exception {
+    private void syncAd() throws Exception {
         if (isDev) return;
         if(!isPrivateDeploy) return;
         List<TimeType> timeTypeList = timeTypeMapper.selectList(new QueryWrapper<TimeType>().eq("sync_ad", 1));

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml

@@ -279,7 +279,7 @@
         departmentName,dp2.department_name as buDepartmentName,department.department_id as departmentId, a.overtime_hours as overtimeHours, a.custom_text as customText, a.project_audit_time as
         projectAuditTime,project_main.name as projectMainName,b.status as projectStatus,DATE_FORMAT(b.finish_date,'%Y-%m-%d') as finishDate,ps.project_category_sub as projectCategorySub,
         GROUP_CONCAT(rlog.operator_id,'@', rlog.operate_date,'@', rlog.msg SEPARATOR '❤') AS logMsg,a.extra_field1 as extraField1,a.extra_field2 as extraField2,a.extra_field3 as extraField3
-        , a.batch_id as batchId,a.sap_service_id as sapServiceId,u2.name as projectManagerName,u2.corpwx_userid as projectManagerCorpwxUserId, multi_degr_id as multiDegrId,project.current_stage_name as stageName
+        , a.batch_id as batchId,a.sap_service_id as sapServiceId,u2.name as projectManagerName,u2.corpwx_userid as projectManagerCorpwxUserId, multi_degr_id as multiDegrId,b.current_stage_name as stageName
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN project_separate AS ps on b.id=ps.id

+ 1 - 0
fhKeeper/formulahousekeeper/timesheet/index.html

@@ -2,6 +2,7 @@
 <html>
   <head>
     <meta charset="utf-8" />
+    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
     <!-- 尝试清除打包缓存 -->
     <!-- <meta http-equiv="pragram" content="no-cache">
         <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">

+ 5 - 0
fhKeeper/formulahousekeeper/timesheet/src/App.vue

@@ -94,4 +94,9 @@
         opacity: 0;
     }
 
+    .resetElEmtClass {
+        .el-dialog__body {
+            padding: 0 !important;
+        }
+    }
 </style>

+ 4 - 0
fhKeeper/formulahousekeeper/timesheet/src/http.js

@@ -59,6 +59,8 @@ export default {
         }
         if(localStorage.getItem('lang') == 'en') {
             data.lang = 'english'
+        } else {
+            data.lang = 'zh'
         }
         axios({
             method: 'post',
@@ -109,6 +111,8 @@ export default {
         }
         if(localStorage.getItem('lang') == 'en') {
             data.lang = 'english'
+        } else {
+            data.lang = 'zh'
         }
         axios({
             method: 'post',

+ 8 - 1
fhKeeper/formulahousekeeper/timesheet/src/i18n/en.json

@@ -2177,5 +2177,12 @@
   "qingJiaJiWeiTianBaoJiShi": "Leave calculation for timely reporting",
   "qingShuRuHeXiaoYuanYing": "Please enter the reason for verification",
   "wuXiaoJiaBan": "Invalid overtime",
-  "yiFaFangJIaBanGongShi": "Overtime pay has been paid"
+  "yiFaFangJIaBanGongShi": "Overtime pay has been paid",
+  "gongJiGongShi": "Total working hours",
+  "queRenZhuanYi": "Confirm transfer",
+  "tiaoShuJu": "Article data",
+  "yiXuanZe": "Selected",
+  "zhuanYIGongShi": "Transfer of working hours",
+  "zhuanYiChengGong": "Transfer successful",
+  "zhuanYiZhi": "Transfer to"
 }

+ 8 - 1
fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.json

@@ -2177,5 +2177,12 @@
   "jiaBanHeXiao": "加班核销",
   "qingShuRuHeXiaoYuanYing": "请输入核销原因",
   "yiFaFangJIaBanGongShi": "已发放加班工资",
-  "wuXiaoJiaBan": "无效加班"
+  "wuXiaoJiaBan": "无效加班",
+  "zhuanYIGongShi": "转移工时",
+  "yiXuanZe": "已选择",
+  "tiaoShuJu": "条数据",
+  "gongJiGongShi": "共计工时",
+  "zhuanYiZhi": "转移至",
+  "queRenZhuanYi": "确认转移",
+  "zhuanYiChengGong": "转移成功"
 }

+ 36 - 28
fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue

@@ -36,7 +36,7 @@
                     <span class="el-dropdown-link userinfo-inner">
                         <i class="el-icon-user" style="font-size:18px" ></i>
                         <!-- {{$t('other.customerService')}} -->
-                        帮助中心
+                        {{ $t('bangZhuZhongXin') }} 
                     </span> 
                     <el-dropdown-menu slot="dropdown">
                         <el-dropdown-item >
@@ -49,14 +49,14 @@
                                 src="../assets/image/code.jpg" />
                             </div>
                             <div v-if="isCorpWX">
-                                <div>扫码添加企业微信客服</div>
+                                <div>{{ $t('saoMaTianJiaQiYeWeiXinKeFu') }}</div>
                                 <img
                                 style="width: 153px; height: 153px"
                                 src="../assets/image/qwcode.png" />
                             </div>
                             <div>
                                 <div>
-                                    <el-link type="primary" :underline="false" href="https://www.ttkuaiban.com/download/%E5%B7%A5%E6%97%B6%E7%AE%A1%E5%AE%B6%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%E4%B9%A6.pdf">点击查看操作手册</el-link>
+                                    <el-link type="primary" :underline="false" href="https://www.ttkuaiban.com/download/%E5%B7%A5%E6%97%B6%E7%AE%A1%E5%AE%B6%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%E4%B9%A6.pdf">{{ $t('dianJiChaKanCaoZuoShouCe') }}</el-link>
                                 </div>
                             </div>
                         </el-dropdown-item>
@@ -155,7 +155,7 @@
                         <el-menu-item v-if="item.leaf && item.children.length > 0" :index="item.children[0].path" :data-v-step="item.children[0].path">
                             <i :class="item.iconCls"></i> 
                             <!-- {{item.children[0].name}} -->
-                            <span class="bosx" v-if="$t(item.meta.text).length < 16">{{$t(item.meta.text)}}</span>
+                            <span class="bosx" v-if="$t(item.meta.text).length <= 16">{{$t(item.meta.text)}}</span>
                             <el-tooltip class="itemName bosx"  v-if="$t(item.meta.text).length > 16" effect="dark" :content="$t(item.meta.text)" placement="top">
                                 <span>{{$t(item.meta.text)}}</span>
                             </el-tooltip>
@@ -236,43 +236,43 @@
                 </el-dialog>
 
                 <el-dialog
-                    title="修改公司名称"
+                    :title="$t('xiuGaiGongSiMingCheng')"
                     :visible.sync="editCompanyNamedialog"
                     width="30%">
                     <el-form :model="companyForm" :rules="rules" ref="companyForm" label-width="100px" class="demo-ruleForm">
-                        <el-form-item label="公司名称" prop="name">
+                        <el-form-item :label="$t('gongSiMingCheng')" prop="name">
                             <el-input v-model.trim="companyForm.name"></el-input>
                         </el-form-item>
                     </el-form>
                     <span slot="footer" class="dialog-footer">
-                        <el-button @click="editCompanyNamedialog = false">取 消</el-button>
-                        <el-button type="primary" @click="editCompanyName('companyForm')">确 定</el-button>
+                        <el-button @click="editCompanyNamedialog = false">{{ $t('quXiao') }}</el-button>
+                        <el-button type="primary" @click="editCompanyName('companyForm')">{{ $t('queDing') }}</el-button>
                     </span>
                 </el-dialog>
             </section>
         </el-col>
 
         <!-- 完善工号弹窗 -->
-        <el-dialog title="完善工号" :visible.sync="perfectJobNumber" width="500px" :show-close="false">
+        <el-dialog :title="$t('wanShanGongHao')" :visible.sync="perfectJobNumber" width="500px" :show-close="false">
             <el-form :model="perfectForm" :rules="rules" ref="perfectForm" label-width="80px" class="demo-ruleForm">
-                <el-form-item label="工号" prop="jobNumber">
+                <el-form-item :label="$t('Worknumber')" prop="jobNumber">
                     <el-input v-model.trim="perfectForm.jobNumber"></el-input>
                 </el-form-item>
             </el-form>
             <span slot="footer" class="dialog-footer">
-                <el-button type="primary" @click="editPerfectJobNumber('perfectForm')">确 定</el-button>
+                <el-button type="primary" @click="editPerfectJobNumber('perfectForm')">{{ $t('queDing') }}</el-button>
             </span>
         </el-dialog>
 
         <!-- 完善名称弹窗 -->
-        <el-dialog title="完善姓名" :visible.sync="perfectName" width="500px" :show-close="false">
+        <el-dialog :title="$t('wanShanXingMing')" :visible.sync="perfectName" width="500px" :show-close="false">
             <el-form :model="perfectFormName" :rules="rules" ref="perfectFormName" label-width="80px" class="demo-ruleForm">
-                <el-form-item label="姓名" prop="userName">
+                <el-form-item :label="$t('lable.name')" prop="userName">
                     <el-input v-model.trim="perfectFormName.userName"></el-input>
                 </el-form-item>
             </el-form>
             <span slot="footer" class="dialog-footer">
-                <el-button type="primary" @click="editPerfectName('perfectFormName')">确 定</el-button>
+                <el-button type="primary" @click="editPerfectName('perfectFormName')">{{$t('queDing')}}</el-button>
             </span>
         </el-dialog>
     </el-row>
@@ -285,6 +285,7 @@
         inject:['reloads'],
         data() {
             return {
+                textLength: 16,
                 companyForm:{
                     name: '',
                 },
@@ -296,14 +297,14 @@
                 },
                 rules: {
                     name: [
-                        { required: true, message: '请输入公司名称', trigger: 'blur' },
-                        { min: 1, max: 20, message: '长度为1-20个字符', trigger: 'blur' }
+                        { required: true, message: this.$t('qingShuRuGongSiMingCheng'), trigger: 'blur' },
+                        { min: 1, max: 20, message: this.$t('changDuWei_120GeZiFu'), trigger: 'blur' }
                     ],
                     jobNumber: [
-                        { required: true, message: '请输入工号', trigger: 'blur' }
+                        { required: true, message: this.$t('qingShuRuGongHao'), trigger: 'blur' }
                     ],
                     userName: [
-                        { required: true, message: '请输入姓名', trigger: 'blur' }
+                        { required: true, message: this.$t('defaultText.PleaseEnterYourName'), trigger: 'blur' }
                     ]
                 },
                 tourFlg: false,
@@ -359,10 +360,10 @@
                     startTimeout: 1000,   //1秒后执行
                     highlight: true,
                     labels: {
-                        buttonSkip: '跳过',
-                        buttonPrevious: '上一步',
-                        buttonNext: '下一步',
-                        buttonStop: '关闭'
+                        buttonSkip: this.$t('tiaoGuo'),
+                        buttonPrevious: this.$t('btn.previousstep'),
+                        buttonNext: this.$t('btn.nextStep'),
+                        buttonStop: this.$t('Shutdown')
                     }
                 },
                 myCallbacks: {
@@ -642,7 +643,7 @@
                 var h = util.formatDate.cdTime(new Date(new Date().getTime() + this.user.remainingTime), new Date(), 'h');
                 var m = util.formatDate.cdTime(new Date(new Date().getTime() + this.user.remainingTime), new Date(), 'm');
                 var s = util.formatDate.cdTime(new Date(new Date().getTime() + this.user.remainingTime), new Date(), 's');
-                this.remainingTime = d+'天'+h+'时'+m+'分'+s+'秒';
+                this.remainingTime = d+this.$t('time.day')+h+this.$t('shi')+m+this.$t('fen')+s+this.$t('miao');
             },
 
             // 加载消息
@@ -825,7 +826,7 @@
                                             fail: function (res) {
                                                 console.log('查看错误信息', res)
                                                 if (res.errMsg.indexOf('function not exist') > -1) {
-                                                    alert('版本过低请升级')
+                                                    alert(that.$t('banBenGuoDiQingShengJi'))
                                                 }
                                             },
                                         })
@@ -833,7 +834,7 @@
                                 }, (error) => {
                                     console.log('查看错误信息' + res)
                                     if (error.errMsg.indexOf('function not exist') > -1) {
-                                        alert('版本过低请升级')
+                                        alert(that.$t('banBenGuoDiQingShengJi'))
                                     }
                                 })
                         });
@@ -861,7 +862,7 @@
                                 }
                                 sessionStorage.setItem('user', JSON.stringify(nerUser));
                                 this.$message({
-                                    message: '操作成功',
+                                    message: this.$t('operationissuccessful'),
                                     type: "success"
                                 });
                             } else {
@@ -898,7 +899,7 @@
                                 }
                                 sessionStorage.setItem('user', JSON.stringify(nerUser));
                                 this.$message({
-                                    message: '操作成功',
+                                    message: this.$t('operationissuccessful'),
                                     type: "success"
                                 });
                             } else {
@@ -976,7 +977,7 @@
             }
 
             // 判断是否为新用户
-            if(this.user.isFirstLogin == 1 && this.user.roleName == '超级管理员' && this.firstTourFalse != 'false' && this.user.createTime[0] > '2022') {
+            if(this.user.isFirstLogin == 1 && this.user.roleName == this.$t('role.superAdministrator') && this.firstTourFalse != 'false' && this.user.createTime[0] > '2022') {
                 var thats = this
                 this.tourFlg = true
                 setTimeout(() => {
@@ -999,6 +1000,13 @@
             if(this.user.dingdingUserid) {
                 this.setDDOpenData()
             }
+
+            // 中英文显示字符长度
+            if(this.language == '中文') {
+                this.textLength = 16
+            } else {
+                this.textLength = 17
+            }
         },
     };
 </script>

+ 11 - 2
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -150,6 +150,7 @@
                                     <el-link type="primary" v-if="user.timeType.pushReportData == 1 && permissions.reportPush" :underline="false" @click="pushWorkTime">{{ $t('tuiSongGongShi') }}</el-link>
                                     <el-link type="primary" v-if="user.timeType.pushReportData == 1 && user.companyId==3092 && permissions.reportPush" :underline="false" @click="pushWorkTimeLogDig=true,getPushWorkLogData()">{{ $t('gongShiTuiSongRiZhi') }}</el-link>
                                     <el-link type="primary" v-if="user.roleName == $t('role.superAdministrator') && user.companyId==839" :underline="false" @click="reportLogCheckDialog=true">{{ $t('riBaoShenHeXiuGai') }}</el-link>
+                                    <el-link type="primary" v-if="(user.roleName == $t('role.superAdministrator') || user.roleName == $t('role.systemAdministrator')) && user.companyId==936" :underline="false" @click="transferWorkingHoursVisable=true">{{ $t('zhuanYIGongShi') }}</el-link>
                                     <!-- <el-button v-if="user.timeType.pushReportData == 1 && permissions.reportPush" style="margin-left:10px;" icon="iconfont firerock-icontuisong" size="mini" @click="pushWorkTime"></el-button> -->
                                 </span>
                             </div>
@@ -2162,6 +2163,8 @@
             </div>
         </el-dialog>
         
+        <!-- 威派格定制 -->
+        <TransferWorkingHours v-model="transferWorkingHoursVisable" :projectList="projectList" :userList="usersList"></TransferWorkingHours>
     </section>
 </template>
 
@@ -2179,6 +2182,9 @@
 
     // 重庆物奇定制组件
     import WeeklyCustomization from "./weeklyCustomization.vue"
+
+    // 威派格定制转移工时
+    import TransferWorkingHours from "./transferWorkingHours.vue"
     
     import { mapMutations } from 'vuex'
     let _that = this
@@ -2188,7 +2194,8 @@
             selectCat,
             vueCascader,
             WeeklyCustomization,
-            vueMultipleDept
+            vueMultipleDept,
+            TransferWorkingHours
         },
         data() {
             return {
@@ -2507,6 +2514,8 @@
                 isReminder:true,
                 reportLogCheckDialog:false,
                 deptIdForHasReport:[],
+
+                transferWorkingHoursVisable: false
             };
         },
         watch: {
@@ -5839,7 +5848,7 @@
                     if (res.code == "ok") {
                         var filePath = res.data;
                         const a = document.createElement('a'); // 创建a标签
-                        a.setAttribute('download', this.$t('projectexport') + '.xlsx');// download属性
+                        a.setAttribute('download', this.$t('other.dailyWork') + '.xlsx');// download属性
                         a.setAttribute('href', filePath);// href链接
                         a.click(); //自执行点击事件
                         a.remove();

+ 391 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/transferWorkingHours.vue

@@ -0,0 +1,391 @@
+<template>
+    <div class="resetElEmtClass">
+        <el-dialog :title="$t('zhuanYIGongShi')" :visible.sync="modelValue" width="96vw" :top="'4vh'"
+            :before-close="handleClose">
+            <div class="transferWorkingHours">
+                <!-- 筛选条件 -->
+                <div class="transferWorkingHours-title">
+                    <el-form :inline="true" :model="filterCriteriaForm" class="demo-form-inline">
+                        <el-form-item :label="$t('ren-yuan')">
+                            <el-select v-model="filterCriteriaForm.userList" multiple filterable
+                                :placeholder="$t('defaultText.pleaseChoose')" clearable collapse-tags size="small"
+                                @change="filterSelect()" v-if="user.userNameNeedTranslate != 1">
+                                <el-option v-for="item in allUserList" :key="item.id" :label="item.name" :value="item.id">
+                                </el-option>
+                            </el-select>
+                            <selectCat :filterable="true" :size="'small'" v-if="user.userNameNeedTranslate == 1"
+                                :subject="allUserList" :clearable="true" :multiSelect="true" :distinction="'1'"
+                                :expandPersonnel="false" @selectCal="selectCal"></selectCat>
+                        </el-form-item>
+                        <el-form-item :label="$t('screening.workingDate')">
+                            <el-date-picker size="small" v-model="filterCriteriaForm.workDate" :editable="false"
+                                format="yyyy-MM-dd" value-format="yyyy-MM-dd" :clearable="true" @change="filterSelect()"
+                                :range-separator="$t('other.to')" type="daterange" :start-placeholder="$t('time.startDate')"
+                                :end-placeholder="$t('time.endDate')"></el-date-picker>
+                        </el-form-item>
+                        <el-form-item :label="$t('other.project')">
+                            <el-select v-model="filterCriteriaForm.projectId" filterable clearable
+                                :placeholder="$t('defaultText.pleaseChoose')" size="small" @change="filterSelect()">
+                                <el-option v-for="item in allProjectList" :key="item.id" :label="item.projectName"
+                                    :value="item.id">
+                                    <div class="omitText">
+                                        <div class="left">{{ item.projectName }}</div>
+                                        <div class="right">{{ item.projectCode }}</div>
+                                    </div>
+                                </el-option>
+                            </el-select>
+                        </el-form-item>
+                    </el-form>
+                </div>
+                <!-- 表格 -->
+                <div>
+                    <el-table :data="tableData" ref="multipleTable" height="58vh" border v-loading="tableDataLoading"
+                        @selection-change="handleSelectionChange" style="width: 100%">
+                        <el-table-column align="center" type="selection" width="55"></el-table-column>
+                        <el-table-column align="center" prop="jobNumber" :label="$t('Worknumber')"
+                            width="180"></el-table-column>
+                        <el-table-column align="center" prop="userName" :label="$t('lable.name')" width="180">
+                            <template slot-scope="scope">
+                                <TranslationOpenDataText type='userName' :openid='scope.row.userName'>
+                                </TranslationOpenDataText>
+                            </template>
+                        </el-table-column>
+                        <el-table-column align="center" prop="deptName" :label="$t('subordinatedepartments')" width="180">
+                            <template slot-scope="scope">
+                                <TranslationOpenDataText type='departmentName' :openid='scope.row.deptName'>
+                                </TranslationOpenDataText>
+                            </template>
+                        </el-table-column>
+                        <el-table-column align="center" prop="projectCode" :label="$t('Itemno')"
+                            width="240"></el-table-column>
+                        <el-table-column align="center" prop="projectName" :label="$t('headerTop.projectName')"
+                            width="240"></el-table-column>
+                        <el-table-column align="center" prop="createDate" :label="$t('screening.workingDate')"
+                            width="180"></el-table-column>
+                        <el-table-column align="center" prop="workingTime" :label="$t('screening.workTime')"
+                            width="100"></el-table-column>
+                        <el-table-column align="center" prop="groupName" :label="$t('other.taskGroup')"
+                            width="180"></el-table-column>
+                        <el-table-column align="center" prop="stageName" :label="$t('other.inputStage')"
+                            width="180"></el-table-column>
+                    </el-table>
+                </div>
+                <!-- 分页 -->
+                <div class="transferWorkingHours-paging">
+                    <div>{{ $t('yiXuanZe') }} {{ tableSelected.length }} {{ $t('tiaoShuJu') }},{{ $t('gongJiGongShi') }}:{{
+                        totalWorkingHours }} {{ $t('time.hour') }}</div>
+                    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
+                        :current-page="pagingForm.pageIndex" :page-sizes="[30, 50, 100, 150, 200, 300]"
+                        :page-size="pagingForm.pageSize" layout="prev, pager, next, sizes" :total="pagingTotal">
+                    </el-pagination>
+                </div>
+                <!-- 转移至 -->
+                <div slot="footer">
+                    <el-form :inline="true" :model="transform" class="demo-form-inline">
+                        <el-form-item :label="$t('zhuanYiZhi')">
+                            <el-select v-model="transform.projectId" filterable clearable
+                                :placeholder="$t('defaultText.pleaseChoose')" size="small" :disabled="!tableSelected.length"
+                                @change="changeProject()">
+                                <el-option v-for="item in allProjectList" :key="item.id" :label="item.projectName"
+                                    :value="item.id">
+                                    <div class="omitText">
+                                        <div class="left">{{ item.projectName }}</div>
+                                        <div class="right">{{ item.projectCode }}</div>
+                                    </div>
+                                </el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item>
+                            <el-select v-model="transform.taskGroupingId" filterable clearable
+                                :placeholder="$t('defaultText.pleaseSelectaTaskGroup')" :disabled="!transform.projectId"
+                                size="small" @change="changeTaskGroup()">
+                                <el-option v-for="item in taskGroupingList" :key="item.id" :label="item.name"
+                                    :value="item.id"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item>
+                            <el-select v-model="transform.stageId" filterable clearable
+                                :placeholder="$t('pleaseselecttheprojectphase')"
+                                :disabled="!(transform.projectId && transform.taskGroupingId)" size="small">
+                                <el-option v-for="item in stageList" :key="item.id" :label="item.stagesName"
+                                    :value="item.id">
+                                </el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item>
+                            <el-button type="primary" :size="'small'" :loading="confirmTransformLoading"
+                                @click="confirmTransform()"
+                                :disabled="!(transform.projectId && transform.taskGroupingId && transform.stageId)">{{
+                                    $t('queRenZhuanYi') }}</el-button>
+                        </el-form-item>
+                    </el-form>
+                </div>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import selectCat from "@/components/select.vue"
+export default {
+    name: '',
+    components: {
+        selectCat
+    },
+    props: {
+        modelValue: {
+            type: Boolean,
+            default: () => false
+        },
+        projectList: {
+            type: Array,
+            default: () => []
+        },
+        userList: {
+            type: Array,
+            default: () => []
+        }
+    },
+    data() {
+        return {
+            user: JSON.parse(sessionStorage.getItem("user")),
+            allProjectList: [],
+            allUserList: [],
+            taskGroupingList: [],
+            stageList: [],
+            transform: {
+                projectId: '',
+                taskGroupingId: '',
+                stageId: ''
+            },
+            filterCriteriaForm: {
+                userList: [],
+                workDate: [],
+                projectId: ''
+            },
+            pagingForm: {
+                pageIndex: 1,
+                pageSize: 100
+            },
+            pagingTotal: 0,
+            tableSelected: [],
+            tableData: [],
+            tableDataLoading: false,
+            confirmTransformLoading: false
+        }
+    },
+    computed: {
+        totalWorkingHours() {
+            return this.tableSelected.reduce((total, item) => {
+                let num = item.workingTime || 0
+                return total + Number(num)
+            }, 0)
+        }
+    },
+    watch: {
+        modelValue(val) {
+            if (val) {
+                this.emptyFilterData()
+                this.getTableList()
+            }
+            this.updateModelValue()
+        },
+        projectList(val) {
+            this.allProjectList = val
+        },
+        userList(val) {
+            this.allUserList = val
+        }
+    },
+    model: {
+        prop: 'modelValue',
+        event: 'getValue'
+    },
+    created() { },
+    mounted() { },
+    methods: {
+        async confirmTransform() {
+            const { projectId, taskGroupingId, stageId } = this.transform
+            const reportIds = this.tableSelected.map(item => item.reportId).join(',')
+            this.confirmTransformLoading = true
+            const { data, code } = await this.postData('/report/transferReport', {
+                reportIds, projectId, stageId,
+                groupId: taskGroupingId,
+            })
+
+            if (code == 'ok') {
+                this.$message({
+                    message: this.$t('zhuanYiChengGong'),
+                    type: "success"
+                });
+                this.pagingForm.pageIndex = 1
+                this.emptyBasicData()
+                this.getTableList()
+            }
+            this.confirmTransformLoading = false
+        },
+        async getTableList() {
+            const { userList, workDate, projectId } = this.filterCriteriaForm
+            this.tableDataLoading = true
+            const { data } = await this.postData('/report/getReportListWithTransfer ', {
+                startDate: workDate[0],
+                endDate: workDate[1],
+                userIds: userList.join(','),
+                projectId: projectId,
+                ...this.pagingForm
+            })
+            this.tableDataLoading = false
+            this.tableData = data.result
+            this.pagingTotal = data.count
+        },
+        async getTaskGroups() {
+            const { projectId } = this.transform
+            let { data } = await this.postData('/task-group/listMyJoinGroup', {
+                projectId,
+                isSubstitude: 1
+            })
+            this.taskGroupingList = data
+        },
+        async getGroupStages() {
+            const { taskGroupingId } = this.transform
+            let { data } = await this.postData('/stages/getProjectStagesByGroup', {
+                groupId: taskGroupingId
+            })
+            this.stageList = data
+        },
+        filterSelect() {
+            this.pagingForm.pageIndex = 1
+            this.getTableList()
+        },
+        emptyBasicData() {
+            this.transform = {
+                projectId: '',
+                taskGroupingId: '',
+                stageId: ''
+            }
+            this.taskGroupingList = []
+            this.stageList = []
+        },
+        emptyFilterData() {
+            this.filterCriteriaForm = {
+                userList: [],
+                workDate: [],
+                projectId: ''
+            }
+        },
+        changeTaskGroup() {
+            const { taskGroupingId } = this.transform
+            if (taskGroupingId) {
+                this.getGroupStages()
+            } else {
+                this.transform = {
+                    ...this.transform,
+                    stageId: ''
+                }
+                this.stageList = []
+            }
+        },
+        changeProject() {
+            const { projectId } = this.transform
+            if (projectId) {
+                this.getTaskGroups()
+            } else {
+                this.transform = {
+                    projectId: '',
+                    taskGroupingId: '',
+                    stageId: ''
+                }
+                this.taskGroupingList = []
+                this.stageList = []
+            }
+        },
+        handleSelectionChange(row) {
+            this.tableSelected = row
+        },
+        handleSizeChange(size) {
+            this.pagingForm = {
+                pageIndex: 1,
+                pageSize: size
+            }
+            this.getTableList()
+        },
+        handleCurrentChange(page) {
+            this.pagingForm.pageIndex = page
+            this.getTableList()
+        },
+        updateModelValue() {
+            this.$emit('getValue', this.modelValue);
+            this.$emit('change', this.modelValue);
+        },
+        selectCal(obj) {
+            if (obj.distinction == 1) {
+                let userListId = obj.arrUserList
+                let arr = []
+                for (var i in userListId) {
+                    arr.push(userListId[i].id)
+                }
+                this.filterCriteriaForm.userList = arr
+                this.filterSelect()
+            }
+        },
+        // 封装 post 请求
+        postData(url, params) {
+            return new Promise((resolve, reject) => {
+                this.http.post(url, { ...params },
+                    res => {
+                        if (res.code == 'ok') {
+                            resolve(res)
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                            reject(error)
+                        }
+                    },
+                    error => {
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        reject(error)
+                    })
+            })
+        },
+    },
+}
+</script>
+<style scoped lang='scss'>
+.omitText {
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+
+    .left {
+        max-width: 300px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+
+    .right {
+        flex: 1;
+        color: #8492a6;
+        font-size: 13px;
+        margin-left: 10px;
+        text-align: right;
+    }
+}
+
+.transferWorkingHours {
+    padding: 0 20px;
+
+    .transferWorkingHours-paging {
+        margin: 10px 0;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+    }
+}
+</style>