finance.vue 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. <template>
  2. <section>
  3. <!--工具条-->
  4. <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
  5. <el-form :inline="true">
  6. <!-- <el-form-item label="财务核算成本 | 月份选择" style="margin-top:5px;"> -->
  7. <el-form-item label="月份选择" style="margin-top:5px;">
  8. <el-date-picker size="small" v-model="date" :editable="false" format="yyyy-MM" value-format="yyyy-MM" @change="changeMonth" :clearable="false" type="month" placeholder="选择月份" style="margin-right: 20px"></el-date-picker>
  9. <el-link type="primary" :underline="false" @click="audits()">待审核</el-link>
  10. </el-form-item>
  11. <!-- <el-radio-group v-model="radio" @change="switchList" style="margin-left:160px;margin-top:5px;"> -->
  12. <el-radio-group v-model="radio" @change="switchList" style="margin-left:80px;margin-top:5px;">
  13. <el-radio-button label="全部人员" >全部人员({{allFinanceList.length}})</el-radio-button>
  14. <el-radio-button label="无项目工时人员">无项目工时人员({{noReportUserList.length}})</el-radio-button>
  15. </el-radio-group>
  16. <el-form-item v-if="user.role == 1 || user.role == 2 || user.role == 4" style="margin-left:5px;margin-top:5px;">
  17. <el-link type="primary" :underline="false" @click="showSettingDialog()" >分摊比例设置</el-link>
  18. </el-form-item>
  19. <el-form-item style="float:right;" v-if="user.role == 1 || user.role == 2 || user.role == 4">
  20. <el-link type="primary" :underline="false" @click="getTemplate()" >财务模板下载</el-link>
  21. </el-form-item>
  22. <!-- <el-form-item style="float:right;">
  23. <el-upload ref="upload" action="#" :limit="1" :http-request="importFinance" :show-file-list="false">
  24. <el-link type="primary" :underline="false" >财务数据上传</el-link>
  25. </el-upload>
  26. </el-form-item> -->
  27. <el-form-item style="float:right;" v-if="user.role == 1 || user.role == 2 || user.role == 4">
  28. <el-link type="primary" :underline="false" @click="importDialog = true;isUploading=false;">财务数据上传</el-link>
  29. </el-form-item>
  30. <el-form-item style="float:right;" v-if="user.role == 1 || user.role == 2 || user.role == 4">
  31. <el-link type="primary" :underline="false" @click="showItemDialog">自定义薪资项</el-link>
  32. </el-form-item>
  33. <el-form-item style="float:right;" v-if="user.role == 1 || user.role == 2 || user.role == 4">
  34. <el-link type="primary" :underline="false" @click="reviewerVisible = true">设置审核人</el-link>
  35. </el-form-item>
  36. </el-form>
  37. </el-col>
  38. <!-- 财务报表审核 -->
  39. <el-dialog :title="shenhe" :visible.sync="importVisible" width="650px" :before-close="handleClose">
  40. <div>
  41. <el-radio-group v-model="tabPosition" style="margin-bottom: 20px;">
  42. <el-radio-button label="1">待审核</el-radio-button>
  43. <el-radio-button label="2">以驳回</el-radio-button>
  44. </el-radio-group>
  45. <el-table :data="tableData" style="width: 100%" :height="400">
  46. <el-table-column prop="date" label="日期"></el-table-column>
  47. <el-table-column prop="date" label="操作人"></el-table-column>
  48. <el-table-column prop="date" label="操作"></el-table-column>
  49. </el-table>
  50. </div>
  51. </el-dialog>
  52. <!-- 设置审核人弹窗 -->
  53. <el-dialog title="设置审核人" :visible.sync="reviewerVisible" width="350px" :before-close="handleCloses">
  54. <el-form :model="reviewerRuleForm" ref="reviewerRuleForm" label-width="100px" class="demo-ruleForm">
  55. <el-form-item label="选择审核人" prop="auditorId" :rules="{required: true, message: '审核人不能为空', trigger: 'blur'}">
  56. <el-select v-model="reviewerRuleForm.auditorId" clearable placeholder="请选择审核人" >
  57. <el-option v-for="(item, index) in people" :key="index" :label="item.name" :value="item.id"></el-option>
  58. </el-select>
  59. </el-form-item>
  60. <el-form-item>
  61. <el-button type="primary" @click="submitreviewerRuleForm('reviewerRuleForm')">提交</el-button>
  62. </el-form-item>
  63. </el-form>
  64. </el-dialog>
  65. <!--列表-->
  66. <!-- 222 -->
  67. <el-table :data="list" highlight-current-row v-loading="listLoading"
  68. show-summary=true
  69. ref="table"
  70. :height="300" style="width: 100%;">
  71. <el-table-column prop="name" label="姓名" sortable width="150"></el-table-column>
  72. <el-table-column :prop="headerCols[index]" :label="item" sortable show-overflow-tooltip v-for="(item, index) in tblCols"
  73. :key="index">
  74. </el-table-column>
  75. <!-- <el-table-column prop="monthCost" label="customCols.monthCost" width="150"></el-table-column>
  76. <el-table-column prop="bonus" :label="customCols.bonus" ></el-table-column>
  77. <el-table-column prop="allowance" :label="customCols.allowance" ></el-table-column>
  78. <el-table-column prop="insuranceOld" :label="customCols.insuranceOld" ></el-table-column>
  79. <el-table-column prop="insuranceMedical" :label="customCols.insuranceMedical" ></el-table-column>
  80. <el-table-column prop="insuranceLosejob" :label="customCols.insuranceLosejob" ></el-table-column>
  81. <el-table-column prop="insuranceInjury" :label="customCols.insuranceInjury" ></el-table-column>
  82. <el-table-column prop="houseFund" :label="customCols.houseFund" ></el-table-column> -->
  83. <!-- <el-table-column prop="field1" :label="customCols.field1" ></el-table-column>
  84. <el-table-column prop="field2" :label="customCols.field2" ></el-table-column>
  85. <el-table-column prop="field3" :label="customCols.field3" ></el-table-column> -->
  86. <!-- <el-table-column prop="monthCost" :label="customCols.monthCost" width="150"></el-table-column>
  87. <el-table-column prop="bonus" :label="customCols.bonus" ></el-table-column>
  88. <el-table-column prop="allowance" :label="customCols.allowance" ></el-table-column>
  89. <el-table-column prop="insuranceOld" :label="customCols.insuranceOld" ></el-table-column>
  90. <el-table-column prop="insuranceMedical" :label="customCols.insuranceMedical" ></el-table-column>
  91. <el-table-column prop="insuranceLosejob" :label="customCols.insuranceLosejob" ></el-table-column>
  92. <el-table-column prop="insuranceInjury" :label="customCols.insuranceInjury" ></el-table-column>
  93. <el-table-column prop="houseFund" :label="customCols.houseFund" ></el-table-column>
  94. <el-table-column prop="field1" :label="customCols.field1" ></el-table-column>
  95. <el-table-column prop="field2" :label="customCols.field2" ></el-table-column>
  96. <el-table-column prop="field3" :label="customCols.field3" ></el-table-column> -->
  97. <!-- <el-table-column prop="others" label="其他" ></el-table-column> -->
  98. <!-- <el-table-column :label="item.fieldName" v-for="(item, index) in customCols" :key="item.id" :prop="index==0?'customField1':(index==1?'customField2':(index==2?'customField3':''))">
  99. <template slot-scope="scope">
  100. {{index==0?scope.row.customField1:(index==1?scope.row.customField2:(index==2?scope.row.customField3:''))}}
  101. </template>
  102. </el-table-column> -->
  103. <el-table-column prop="totalCost" label="总成本" ></el-table-column>
  104. </el-table>
  105. <el-form :inline="true" >
  106. <el-form-item >
  107. <!-- <el-checkbox style="margin-left:10px;" v-model="assignNoProUser" @click="assignToProject">均摊无项目人员成本</el-checkbox> -->
  108. <!-- <el-button type="primary" :underline="false" size="small" @click="assignNoProUser=false;assignToProject();" style="margin-left:10px;">分摊已填工时人员成本</el-button>
  109. <el-button type="primary" :underline="false" size="small" @click="assignNoProUser=true;assignToProject();" style="margin-left:10px;">分摊全部人员成本</el-button> -->
  110. <el-radio-group v-model="costListRadio" @change="switchCostList" style="margin-left:5px;margin-top:5px;">
  111. <el-radio-button label="1" >分摊已填工时人员成本</el-radio-button>
  112. <el-radio-button label="2">分摊全部人员成本</el-radio-button>
  113. </el-radio-group>
  114. </el-form-item>
  115. <el-form-item style="float:right;">
  116. <el-link type="primary" :underline="false" @click="exportData">导出成本数据</el-link>
  117. </el-form-item>
  118. <!-- <el-form-item style="float:right;margin-right:30px;" v-if="hasNoProjectUsers">
  119. <el-link type="primary" :underline="false" @click="showNoProjectUsers">查看无项目数据</el-link>
  120. </el-form-item> -->
  121. </el-form>
  122. <div id="container" style="height:300px"></div>
  123. <!--新增界面-->
  124. <el-dialog :title="title" v-if="addFormVisible" :visible.sync="addFormVisible" :close-on-click-modal="false" customClass="customWidth" width="600px">
  125. <el-form ref="form1" :model="addForm" :rules="rules" label-width="100px">
  126. <el-form-item label="项目编号" >
  127. <el-input v-model="addForm.code" placeholder="请输入项目编号" clearable></el-input>
  128. </el-form-item>
  129. <el-form-item label="项目名称" prop="name">
  130. <el-input v-model="addForm.name" placeholder="请输入项目名称" clearable></el-input>
  131. </el-form-item>
  132. <el-form-item label="全部参与者">
  133. <el-select v-model="addForm.userId" multiple filterable placeholder="请选择参与者" style="width:100%;" @change="changeParticipator">
  134. <el-option v-for="item in users" :key="item.id" :label="item.name" :value="item.id"></el-option>
  135. </el-select>
  136. </el-form-item>
  137. <el-form-item label="主要负责人" >
  138. <el-select v-model="addForm.inchargerId" :disabled="addForm.userId.length==0" filterable placeholder="请选择负责人" style="width:100%;" @change="changeIncharger">
  139. <el-option v-for="item in participator" :key="item.id" :label="item.name" :value="item.id"></el-option>
  140. </el-select>
  141. </el-form-item>
  142. </el-form>
  143. <div slot="footer" class="dialog-footer">
  144. <el-button @click.native="addFormVisible = false">取消</el-button>
  145. <el-button type="primary" @click="submitInsert" :loading="addLoading">提交</el-button>
  146. </div>
  147. </el-dialog>
  148. <!--用户详细信息弹出框-->
  149. <el-dialog title="查看详情" v-if="userDetailVisible" :visible.sync="userDetailVisible" :close-on-click-modal="false" customClass="customWidth" width="400px">
  150. <div class="line"><span>姓名</span><span>{{userDetail.name}}</span></div>
  151. <div class="line"><span>手机号码</span><span>{{userDetail.phone}}</span></div>
  152. <div class="line"><span>部门</span><span>{{userDetail.departmentName}}</span></div>
  153. <div class="line"><span>成本</span><span>{{userDetail.cost}}元/小时</span></div>
  154. <div slot="footer" class="dialog-footer">
  155. <el-button type="primary" @click="userDetailVisible = false" >确定</el-button>
  156. </div>
  157. </el-dialog>
  158. <!--导入时的设置界面 -->
  159. <el-dialog title="财务数据导入" v-if="importDialog" :visible.sync="importDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
  160. <el-form ref="form3" :model="importParam" >
  161. <el-form-item label="导入月份" >
  162. <!-- <div style="color:orange;">{{date}}</div> -->
  163. <el-date-picker v-model="date" type="month" placeholder="选择月份" format="yyyy-MM" value-format="yyyy-MM"></el-date-picker>
  164. </el-form-item>
  165. <el-form-item prop="syncHistoryReport" >
  166. <el-checkbox label="重新计算该月已填日报成本" v-model="importParam.syncHistoryReport"></el-checkbox>
  167. </el-form-item>
  168. <el-form-item prop="syncUserCost" >
  169. <el-checkbox label="同步到组织架构中员工月薪成本" v-model="importParam.syncUserCost" ></el-checkbox>
  170. </el-form-item>
  171. </el-form>
  172. <div slot="footer" class="dialog-footer">
  173. <el-upload ref="upload" action="#" :limit="1" :http-request="importFinance" :show-file-list="false" >
  174. <el-button type="primary" style="width:100%;" :loading="isUploading" >选择文件并开始导入</el-button>
  175. </el-upload>
  176. </div>
  177. </el-dialog>
  178. <!--无项目人员列表-->
  179. <!-- <el-dialog title="无项目人员列表" v-if="showNPDialog" :visible.sync="showNPDialog" :close-on-click-modal="false" customClass="customWidth" width="1200px">
  180. <el-table :data="npUserList" highlight-current-row v-loading="listLoading"
  181. show-summary=true
  182. ref="table"
  183. :height="400" style="width: 100%;">
  184. <el-table-column prop="name" label="姓名" sortable width="150"></el-table-column>
  185. <el-table-column prop="monthCost" label="工资" width="150"></el-table-column>
  186. <el-table-column prop="bonus" label="奖金" ></el-table-column>
  187. <el-table-column prop="allowance" label="津贴" ></el-table-column>
  188. <el-table-column prop="insuranceOld" label="养老保险" ></el-table-column>
  189. <el-table-column prop="insuranceMedical" label="医疗保险" ></el-table-column>
  190. <el-table-column prop="insuranceLosejob" label="失业保险" ></el-table-column>
  191. <el-table-column prop="insuranceInjury" label="工伤保险" ></el-table-column>
  192. <el-table-column prop="houseFund" label="住房公积金" ></el-table-column>
  193. <el-table-column prop="others" label="其他" ></el-table-column>
  194. <el-table-column :label="item.fieldName" v-for="(item, index) in customCols" :key="item.id" :prop="index==0?'customField1':(index==1?'customField2':(index==2?'customField3':''))">
  195. <template slot-scope="scope">
  196. {{index==0?scope.row.customField1:(index==1?scope.row.customField2:(index==2?scope.row.customField3:''))}}
  197. </template>
  198. </el-table-column>
  199. <el-table-column prop="totalCost" label="总成本" ></el-table-column>
  200. </el-table>
  201. <div slot="footer" class="dialog-footer">
  202. <div style="float:left;color:#ff9900;">*以上人员当月尚无投入的项目,请提醒他们填写日报。</div>
  203. <el-button type="primary" @click="showNPDialog = false" >关闭</el-button>
  204. </div>
  205. </el-dialog> -->
  206. <el-dialog title="自定义薪资项" show-header="false" v-if="itemDialog" :visible.sync="itemDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
  207. <div style="margin-left:30px;">
  208. <!-- 111 -->
  209. <span style="color:#999;">薪资表包含以下数据</span>
  210. <p><el-input v-model="customCols.monthCost" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  211. <p><el-input v-model="customCols.bonus" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  212. <p><el-input v-model="customCols.allowance" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  213. <p><el-input v-model="customCols.insuranceOld" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  214. <p><el-input v-model="customCols.insuranceMedical" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  215. <p><el-input v-model="customCols.insuranceLosejob" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  216. <p><el-input v-model="customCols.insuranceInjury" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  217. <p><el-input v-model="customCols.houseFund" placeholder="请输入自定义薪资项名称" style="width:200px;" maxlength="8"></el-input></p>
  218. <p><el-input v-model="customCols.field1" placeholder="请输入自定义薪资项1名称" style="width:200px;" maxlength="8"></el-input></p>
  219. <p><el-input v-model="customCols.field2" placeholder="请输入自定义薪资项2名称" style="width:200px;" maxlength="8"></el-input></p>
  220. <p><el-input v-model="customCols.field3" placeholder="请输入自定义薪资项3名称" style="width:200px;" maxlength="8"></el-input></p>
  221. </div>
  222. <div slot="footer" class="dialog-footer">
  223. <el-button type="primary" @click="itemDialog = false" >关闭</el-button>
  224. <el-button type="primary" @click="saveItems()" >保存</el-button>
  225. </div>
  226. </el-dialog>
  227. <el-dialog :title="date+'月 无项目工时人员分摊比例设置'" show-header="false" v-if="settingDialog" :visible.sync="settingDialog"
  228. :close-on-click-modal="false" customClass="customWidth" width="1200px">
  229. <div>
  230. <div>
  231. <el-button :disabled="multipleSelection.length==0" @click="setPercent(true, null)">批量设置比例</el-button>
  232. <el-button :disabled="projectCols.length==0 || userCostSettingList.length == 0" @click="getLastMonthSetting">使用上月比例设置</el-button>
  233. <el-button @click="showSelectProjectDialog">管理待分摊项目</el-button>
  234. </div>
  235. <el-table :data="userCostSettingList" highlight-current-row v-loading="costSettingLoading"
  236. ref="settingTable" @selection-change="handleSelectionChange"
  237. :height="400" style="width: 100%;">
  238. <el-table-column type="selection" width="55"></el-table-column>
  239. <el-table-column prop="name" label="姓名" sortable width="90" fixed="left"></el-table-column>
  240. <el-table-column :label="item.projectName" v-for="(item) in projectCols" width="180" size="small"
  241. :key="item.id" align="center">
  242. <template slot-scope="scope">
  243. <span>{{scope.row[item.projectId]}}</span>%
  244. </template>
  245. </el-table-column>
  246. <el-table-column label="设置比例" width="80" fixed="right">
  247. <template slot-scope="scope">
  248. <el-button size="small" @click="setPercent(false,scope.row)">设置</el-button>
  249. </template>
  250. </el-table-column>
  251. </el-table>
  252. </div>
  253. <div slot="footer" class="dialog-footer">
  254. <el-button type="primary" @click="settingDialog = false" >关闭</el-button>
  255. <el-button type="primary" @click="saveMonthSetting()" >保存</el-button>
  256. </div>
  257. </el-dialog>
  258. <el-dialog title="待分摊项目选择" show-header="false" v-if="projectsDialog" :visible.sync="projectsDialog"
  259. :close-on-click-modal="false" customClass="customWidth" width="1000px">
  260. <el-select v-model="chosenProjects" multiple filterable clearable style="width:100%">
  261. <el-option v-for="item in allProjectList" :label="item.projectName" :key="item.id" :value="item.id"></el-option>
  262. </el-select>
  263. <div slot="footer" class="dialog-footer">
  264. <el-button type="default" @click="projectsDialog = false" >关闭</el-button>
  265. <el-button type="primary" @click="saveProjectSetting()" >确定</el-button>
  266. </div>
  267. </el-dialog>
  268. <el-dialog title="设置员工成本各项目占比" show-header="false" v-if="setPercentDialog" :visible.sync="setPercentDialog"
  269. :close-on-click-modal="false" customClass="customWidth" width="600px" >
  270. <div style="margin:0px 10px 10px 10px;">
  271. <span>选择员工</span>
  272. <el-select v-model="chosenNoReportUserIds" multiple filterable clearable style="width:330px;" collapse-tags>
  273. <el-option v-for="item in noReportUserList" :label="item.name" :key="item.id" :value="item.userId"></el-option>
  274. </el-select>
  275. <el-button @click="averageCost" >自动分摊</el-button>
  276. </div>
  277. <el-divider ></el-divider>
  278. <!--项目列表 -->
  279. <el-form v-model="curPercentVal" label-width="365px" style="margin-top:10px;">
  280. <div class="nameList">
  281. <el-form-item v-for="item in projectCols" :label="item.projectName" :key="item.projectId" >
  282. 占比: <el-input v-model="curPercentVal[item.projectId]" style="width:100px;" @input="updatePercentValue"></el-input>&nbsp;%
  283. </el-form-item>
  284. </div>
  285. <el-form-item >
  286. 总比例: {{totalPercent}}&nbsp;%
  287. </el-form-item>
  288. </el-form>
  289. <div slot="footer" class="dialog-footer">
  290. <el-button type="default" @click="setPercentDialog = false" >关闭</el-button>
  291. <el-button type="primary" @click="setPercentSetting()" >确定</el-button>
  292. </div>
  293. </el-dialog>
  294. </section>
  295. </template>
  296. <style scoped>
  297. .line {
  298. padding:10px;
  299. }
  300. .line span{
  301. font-size:18px;
  302. }
  303. .line span:nth-child(even){
  304. float:right;
  305. }
  306. </style>
  307. <script>
  308. import { error } from 'dingtalk-jsapi';
  309. import util from "../../common/js/util";
  310. export default {
  311. data() {
  312. return {
  313. headerCols:['monthCost','bonus', 'allowance', 'insuranceOld', 'insuranceMedical', 'insuranceLosejob', 'insuranceInjury', 'houseFund', 'customField1','customField2','customField3'],
  314. tblCols:[],
  315. costListRadio: 0,
  316. costSettingLoading: false,
  317. chosenNoReportUserIds:[],
  318. curPercentVal:{},
  319. setPercentDialog: false,
  320. chosenProjects:[],
  321. projectsDialog: false,
  322. projectCols:[],
  323. allProjectList:[],
  324. multipleSelection:[],
  325. userCostSettingList: [],
  326. settingDialog: false,
  327. radio:"全部人员",
  328. noReportUserList:[],
  329. allFinanceList:[],
  330. assignNoProUser: false,
  331. customFieldList:[],
  332. itemDialog: false,
  333. customCols:{},
  334. // showNPDialog: false,
  335. npUserList:[],
  336. hasNoProjectUsers: false,
  337. isUploading:false,
  338. importDialog: false,
  339. importParam:{syncUserCost:true, syncHistoryReport:true},
  340. user: JSON.parse(sessionStorage.getItem("user")),
  341. userDetailVisible: false,
  342. userDetail:{},
  343. date: null,
  344. tableHeight: 0,
  345. listLoading: false,
  346. list: [],
  347. addLoading: false,
  348. myChart: null,
  349. params: null,
  350. totalPercent:0,
  351. importVisible: false,
  352. shenhe: '',
  353. tabPosition: '1',
  354. reviewerVisible: false,
  355. reviewerRuleForm: {
  356. auditorId: ''
  357. },
  358. people: []
  359. };
  360. },
  361. methods: {
  362. arrter() {
  363. this.http.post('/user/getEmployeeList', {
  364. departmentId: '-1',
  365. pageIndex: 1,
  366. pageSize: 99999
  367. },res =>{
  368. if(res.code == 'ok') {
  369. this.people = res.data.records
  370. }
  371. },error => {
  372. this.$message({
  373. message: error,
  374. type: "error"
  375. });
  376. })
  377. },
  378. addreviewer() {
  379. this.http.post('/finance-auditor/get', {
  380. companyId: this.user.companyId
  381. },
  382. res => {
  383. if (res.code == "ok") {
  384. console.log(res.data, '数据')
  385. if(res.data) {
  386. this.reviewerRuleForm.auditorId = res.data.auditorId
  387. } else {
  388. this.reviewerRuleForm.auditorId = ''
  389. }
  390. }
  391. },error => {
  392. this.$message({
  393. message: error,
  394. type: "error"
  395. });
  396. }
  397. );
  398. },
  399. // 提交审核人
  400. submitreviewerRuleForm(formName) {
  401. this.$refs[formName].validate((valid) => {
  402. if (valid) {
  403. this.reviewerRuleForm.companyId = this.user.companyId
  404. this.http.post('/finance-auditor/save', this.reviewerRuleForm,
  405. res =>{
  406. if(res.code == 'ok') {
  407. this.$message({
  408. message: '操作成功',
  409. type: "success"
  410. });
  411. this.addreviewer()
  412. } else {
  413. this.$message({
  414. message: '操作失败',
  415. type: "error"
  416. });
  417. }
  418. },error => {
  419. this.$message({
  420. message: error,
  421. type: "error"
  422. });
  423. })
  424. this.reviewerVisible = false
  425. } else {
  426. return false;
  427. }
  428. });
  429. },
  430. handleCloses(done) {
  431. var formName = 'reviewerRuleForm'
  432. this.$refs[formName].resetFields();
  433. done()
  434. },
  435. // 审核
  436. audits() {
  437. this.shenhe = '导入审核'
  438. this.importVisible = true
  439. },
  440. switchCostList() {
  441. //已填日报的人员成本
  442. if (this.costListRadio == 1) {
  443. this.assignNoProUser=false;
  444. this.assignToProject();
  445. } else if (this.costListRadio == 2) {
  446. //全部人员成本
  447. this.assignNoProUser=true;
  448. this.assignToProject();
  449. }
  450. },
  451. getLastMonthSetting() {
  452. this.costSettingLoading = true;
  453. var dataArr = this.date.split('-');
  454. var year = dataArr[0];
  455. var month = dataArr[1];
  456. if (parseInt(month) == 1) {
  457. year = parseInt(year) -1;
  458. month = 12;
  459. } else {
  460. month = parseInt(month) -1;
  461. if (month < 10) {
  462. month = '0'+month;
  463. }
  464. }
  465. var lastMonth = year + '-' + month;
  466. this.http.post('/project-percentage/getMonthSetting', {ymonth: lastMonth},
  467. res => {
  468. this.costSettingLoading = false;
  469. if (res.code == "ok") {
  470. this.projectCols = res.data.financeProjects;
  471. this.allProjectList = res.data.allProjectList;
  472. this.userCostSettingList = res.data.userCostSetting;
  473. //上次如果没有配置过,需要初始化
  474. for (var i=0;i<this.noReportUserList.length; i++) {
  475. var rUser = this.noReportUserList[i];
  476. //检查当前列表中的无项目人员是否在之前的里面存在,如果不在需要加上去
  477. if (this.userCostSettingList.filter(c=>c.id == rUser.userId).length == 0) {
  478. var item = {name: rUser.name, id: rUser.userId};
  479. this.projectCols.forEach(p=>{
  480. item[p.projectId] = 0;
  481. });
  482. this.userCostSettingList.push(item);
  483. }
  484. }
  485. this.$nextTick(()=>{
  486. this.$refs.settingTable.doLayout();
  487. })
  488. } });
  489. },
  490. //获取当月的无项目工时人员的分配比例设置
  491. getMonthSetting() {
  492. this.costSettingLoading = true;
  493. this.http.post('/project-percentage/getMonthSetting', {ymonth: this.date},
  494. res => {
  495. this.costSettingLoading = false;
  496. if (res.code == "ok") {
  497. this.projectCols = res.data.financeProjects;
  498. this.allProjectList = res.data.allProjectList;
  499. this.userCostSettingList = res.data.userCostSetting;
  500. //上次如果没有配置过,需要初始化
  501. for (var i=0;i<this.noReportUserList.length; i++) {
  502. var rUser = this.noReportUserList[i];
  503. console.log('userId====='+rUser.userId);
  504. //检查当前列表中的无项目人员是否在之前的里面存在,如果不在需要加上去
  505. if (this.userCostSettingList.filter(c=>c.id == rUser.userId).length == 0) {
  506. var item = {name: rUser.name, id: rUser.userId};
  507. this.projectCols.forEach(p=>{
  508. item[p.projectId] = 0;
  509. });
  510. this.userCostSettingList.push(item);
  511. }
  512. }
  513. this.$nextTick(()=>{
  514. this.$refs.settingTable.doLayout();
  515. })
  516. } });
  517. },
  518. //提交无工时人员的分配设置
  519. saveMonthSetting() {
  520. //检查数据是否都分配到100%了,防止由于修改了项目列而导致之前的数据不正确的情况
  521. var errorList = this.userCostSettingList.filter(u=>{
  522. let totalPercent = 0.0;
  523. this.projectCols.forEach(p=>{
  524. totalPercent += parseFloat(u[p.projectId]);
  525. });
  526. totalPercent = totalPercent.toFixed(1);
  527. if (totalPercent != 100) {
  528. return true;
  529. } else {
  530. return false;
  531. }
  532. });
  533. if (errorList.length > 0) {
  534. var nameList = errorList.map(e=>e.name);
  535. this.$message({type:'error', message:'存在人员分配比例非100%: '+nameList});
  536. return;
  537. }
  538. this.http.post('/project-percentage/saveMonthSetting', {projectCols: JSON.stringify(this.projectCols),
  539. ymonth: this.date, userSettings: JSON.stringify(this.userCostSettingList)},
  540. res => {
  541. if (res.code == "ok") {
  542. this.$message({type:'success', message:'保存成功'});
  543. this.settingDialog = false;
  544. } else {
  545. this.$message({type:'error', message:'发生错误:'+res.msg});
  546. }});
  547. },
  548. updatePercentValue() {
  549. var total = 0.0;
  550. this.projectCols.forEach(p=>{
  551. total += parseFloat(this.curPercentVal[p.projectId]);
  552. })
  553. this.totalPercent = total.toFixed(1);
  554. this.$forceUpdate();
  555. },
  556. averageCost() {
  557. var avg = (100/this.projectCols.length).toFixed(1);
  558. //最后一个用100减去前面的总和,保证最终合计为100
  559. for (var i=0;i<this.projectCols.length; i++) {
  560. if (i < this.projectCols.length -1) {
  561. this.curPercentVal[this.projectCols[i].projectId] = avg;
  562. } else {
  563. this.curPercentVal[this.projectCols[i].projectId] = (100-avg*(this.projectCols.length-1)).toFixed(1);
  564. }
  565. }
  566. this.updatePercentValue();
  567. this.$forceUpdate();
  568. },
  569. setPercent(isBatch, row) {
  570. this.setPercentDialog = true;
  571. this.chosenNoReportUserIds = [];
  572. if (!isBatch) {
  573. this.chosenNoReportUserIds.push(row.id);
  574. //获取当前比例
  575. this.projectCols.forEach(p=>{
  576. this.curPercentVal[p.projectId] = row[p.projectId];
  577. });
  578. } else {
  579. //批量处理
  580. this.multipleSelection.forEach(m=>{
  581. this.chosenNoReportUserIds.push(m.id);
  582. })
  583. //批量时获取第一条的比例进行加载
  584. this.projectCols.forEach(p=>{
  585. this.curPercentVal[p.projectId] = this.multipleSelection[0][p.projectId];
  586. });
  587. }
  588. this.updatePercentValue();
  589. },
  590. //确认设置的项目列
  591. saveProjectSetting() {
  592. this.projectsDialog = false;
  593. this.projectCols = [];
  594. this.chosenProjects.forEach(c=>{
  595. var item = this.allProjectList.filter(a=>a.id == c)[0];
  596. this.projectCols.push({projectId: item.id, projectName: item.projectName, projectCode: item.projectCode});
  597. });
  598. this.$nextTick(()=>{
  599. this.$refs.settingTable.doLayout();
  600. })
  601. },
  602. handleProjectSelectionChange(val) {
  603. this.projectSelection = val;
  604. },
  605. showSelectProjectDialog() {
  606. //设置选中状态
  607. this.chosenProjects = [];
  608. this.projectCols.forEach(item=>{
  609. this.chosenProjects.push(item.projectId);
  610. })
  611. this.projectsDialog = true;
  612. },
  613. setPercentSetting() {
  614. //检测是否填写的情况下,是否达到100%
  615. if (this.totalPercent != 100) {
  616. this.$message({
  617. message: '分配比例之和必须是100%',
  618. type: "error"
  619. });
  620. return;
  621. }
  622. this.setPercentDialog = false;
  623. this.chosenNoReportUserIds.forEach(u=>{
  624. var targetU = this.userCostSettingList.filter(a=>a.id == u)[0];
  625. //遍历项目
  626. this.projectCols.forEach(p=>{
  627. targetU[p.projectId] = this.curPercentVal[p.projectId];
  628. })
  629. });
  630. this.userCostSettingList.splice(1,0);
  631. },
  632. showSettingDialog() {
  633. this.settingDialog = true;
  634. this.getMonthSetting();
  635. },
  636. handleSelectionChange(val) {
  637. this.multipleSelection = val;
  638. },
  639. switchList() {
  640. if (this.radio == '全部人员') {
  641. this.list = this.allFinanceList;
  642. } else {
  643. this.list = this.noReportUserList;
  644. }
  645. },
  646. downloadByA(row) {
  647. const a = document.createElement('a'); // 创建a标签
  648. a.setAttribute('download', row.name);// download属性
  649. a.setAttribute('href', row.url);// href链接
  650. a.click();// 自执行点击事件
  651. a.remove();
  652. },
  653. getTemplate() {
  654. this.http.post('/finance/getTemplate', {companyId: this.user.companyId},
  655. res => {
  656. if (res.code == "ok") {
  657. if (res.data.indexOf('xlsx') > 0) {
  658. this.downloadByA({name:'财务成本报表.xlsx', url:res.data});
  659. } else {
  660. this.downloadByA({name:'财务成本报表.xls', url:res.data});
  661. }
  662. }});
  663. },
  664. saveItems() {
  665. // let savefields = {
  666. // monthCost : this.customCols.monthCost,
  667. // bonus : this.customCols.bonus,
  668. // allowance : this.customCols.allowance,
  669. // insuranceOld : this.customCols.insuranceOld,
  670. // insuranceMedical : this.customCols.insuranceMedical,
  671. // insuranceLosejob : this.customCols.insuranceLosejob,
  672. // insuranceInjury : this.customCols.insuranceInjury,
  673. // houseFund : this.customCols.houseFund,
  674. // field1 : this.customCols.field1,
  675. // field2 : this.customCols.field2,
  676. // field3 : this.customCols.field3
  677. // }
  678. this.http.post('/finance-tblcuscol/save', this.customCols,
  679. res => {
  680. if (res.code == "ok") {
  681. this.itemDialog = false;
  682. this.getCustomColumn();
  683. }});
  684. this.$forceUpdate();
  685. },
  686. showItemDialog() {
  687. this.itemDialog = true;
  688. // this.customFieldList = {field1:null,field2:null, field3:null};
  689. // if (this.customCols.field1 !== undefined) {
  690. // this.customFieldList.field1 = this.customCols.field1;
  691. // } else if (this.customCols.field2 !== undefined) {
  692. // this.customFieldList.field2 = this.customCols.field2;
  693. // } else if (this.customCols.field3 !== undefined) {
  694. // this.customFieldList.field3 = this.customCols.field3;
  695. // }
  696. },
  697. //获取自定义的字段
  698. getCustomColumn() {
  699. this.http.post('/finance-tblcuscol/getAll', {companyId: this.user.companyId},
  700. res => {
  701. if (res.code == "ok") {
  702. this.customCols = res.data;
  703. this.tblCols = [];
  704. this.tblCols.push(this.customCols.monthCost);
  705. this.tblCols.push(this.customCols.bonus);
  706. this.tblCols.push(this.customCols.allowance);
  707. this.tblCols.push(this.customCols.insuranceOld);
  708. this.tblCols.push(this.customCols.insuranceMedical);
  709. this.tblCols.push(this.customCols.insuranceLosejob);
  710. this.tblCols.push(this.customCols.insuranceInjury);
  711. this.tblCols.push(this.customCols.houseFund);
  712. if (this.customCols.field1 != null) {
  713. this.tblCols.push(this.customCols.field1);
  714. }
  715. if (this.customCols.field2 != null) {
  716. this.tblCols.push(this.customCols.field2);
  717. }
  718. if (this.customCols.field3 != null) {
  719. this.tblCols.push(this.customCols.field3);
  720. }
  721. }});
  722. },
  723. // },
  724. // getProjects() {
  725. // this.http.post('/finance/getProjects', {companyId: this.user.companyId, yearMonth: this.date},
  726. // res => {
  727. // if (res.code == "ok") {
  728. // this.projectCols = res.data.financeProjects;
  729. // this.allProjectList = res.data.allProjectList;
  730. // }});
  731. // },
  732. // showNoProjectUsers() {
  733. // this.showNPDialog = true;
  734. // this.http.post('/finance/getNoProjectUsers', {yearMonth: this.date},
  735. // res => {
  736. // if (res.code == "ok") {
  737. // this.npUserList = res.data;
  738. // }});
  739. // },
  740. assignToProject(){
  741. var _this = this;
  742. this.http.post('/finance/getTimeCost', {yearMonth: this.date, assignNoProUser: this.assignNoProUser},
  743. res => {
  744. if (res.code == "ok") {
  745. var xList = [], yList = [], list = res.data.costList,
  746. totalMoneyCost = res.data.totalMoneyCost;
  747. var nopCost = 0;
  748. if (res.data.noProjectItem.project != null) {
  749. this.hasNoProjectUsers = true;
  750. nopCost = res.data.noProjectItem.cost;
  751. } else {
  752. this.hasNoProjectUsers = false;
  753. }
  754. for(var i in list) {
  755. xList.push(list[i].project);
  756. yList.push({
  757. "value": list[i].cost,
  758. "id": list[i].id,
  759. "time": list[i].workingTime
  760. });
  761. }
  762. var myChart = echarts.init(document.getElementById("container"));
  763. _this.myChart = myChart;
  764. var option = {
  765. title: {
  766. text: this.assignNoProUser?'成本总计 ' + totalMoneyCost + '元'
  767. +(this.hasNoProjectUsers?",含无项目人员成本 " + nopCost+"元 ":"")
  768. :'成本总计 ' + totalMoneyCost + '元',
  769. left:'left',
  770. },
  771. // 工具箱
  772. toolbox: {
  773. show: true,
  774. feature:{
  775. saveAsImage:{
  776. show:true
  777. },
  778. restore:{
  779. show:true
  780. },
  781. magicType:{
  782. type:['line','bar']
  783. },
  784. }
  785. },
  786. tooltip:{
  787. trigger:'axis',
  788. formatter: function (params,ticket,callback) {
  789. var res = params[0].name + "<br/>工作成本"+" : " + params[0].data.value
  790. + "元 <br/>工作时长"+" : " + params[0].data.time + "小时";
  791. _this.params = params;
  792. return res;
  793. }
  794. },
  795. xAxis: {
  796. data: xList,
  797. axisLabel: {
  798. interval:0,rotate:20
  799. }
  800. },
  801. yAxis: [{
  802. type : 'value',
  803. axisLabel: {
  804. formatter:'{value} (元)'
  805. }
  806. }],
  807. series: [{
  808. name: '工作时长(h)',
  809. type: 'bar',
  810. barMaxWidth: 30,
  811. data: yList,
  812. }]
  813. };
  814. option && myChart.setOption(option,{notMerge: true});
  815. // myChart.getZr().on('click', params => {
  816. // const pointInPixel = [params.offsetX, params.offsetY];
  817. // if (myChart.containPixel('grid', pointInPixel)) {
  818. // console.log(_this.params)
  819. // if(_this.radio=='项目') {
  820. // _this.$router.push("/cost/" + _this.params[0].data.id + "/" + _this.params[0].name);
  821. // }
  822. // }
  823. // });
  824. } else {
  825. this.$message({
  826. message: res.msg,
  827. type: "error"
  828. });
  829. }
  830. },
  831. error => {
  832. this.$message({
  833. message: error,
  834. type: "error"
  835. });
  836. });
  837. },
  838. //导出财务数据
  839. exportData() {
  840. this.listLoading = true;
  841. this.http.post('/finance/exportData', {
  842. date: this.date, assignNoProUser: this.assignNoProUser
  843. },
  844. res => {
  845. this.listLoading = false;
  846. if (res.code == "ok") {
  847. var aTag = document.createElement('a');
  848. aTag.download = "财务成本统计.xls";
  849. aTag.href = res.data;
  850. aTag.click();
  851. } else {
  852. this.$message({
  853. message: res.msg,
  854. type: "error"
  855. });
  856. }
  857. },
  858. error => {
  859. this.listLoading = false;
  860. this.$message({
  861. message: error,
  862. type: "error"
  863. });
  864. });
  865. },
  866. getSummaries(param) {
  867. const { columns, data } = param;
  868. const sums = [];
  869. columns.forEach((column, index) => {
  870. if (index === 0) {
  871. sums[index] = '总价';
  872. return;
  873. }
  874. const values = data.map(item => Number(item[column.property]));
  875. if (!values.every(value => isNaN(value))) {
  876. sums[index] = values.reduce((prev, curr) => {
  877. const value = Number(curr);
  878. if (!isNaN(value)) {
  879. return prev + curr;
  880. } else {
  881. return prev;
  882. }
  883. }, 0);
  884. sums[index] += ' 元';
  885. } else {
  886. sums[index] = 'N/A';
  887. }
  888. });
  889. return sums;
  890. },
  891. changeMonth() {
  892. //改变月份
  893. this.getList();
  894. this.assignToProject();
  895. },
  896. // 批量导入人员
  897. importFinance(item) {
  898. //首先判断文件类型
  899. let str = item.file.name.split(".");
  900. let format = str[str.length - 1];
  901. if (format != "xls" && format != "xlsx") {
  902. this.$message({
  903. message: "请选择.xls或.xlsx文件",
  904. type: "error"
  905. });
  906. } else {
  907. this.listLoading = true;
  908. let formData = new FormData();
  909. formData.append("file", item.file);
  910. formData.append("companyId", this.user.companyId);
  911. formData.append("yearMonth", this.date);
  912. formData.append("syncUserCost", this.importParam.syncUserCost);
  913. formData.append("syncHistoryReport", this.importParam.syncHistoryReport);
  914. this.isUploading = true;
  915. this.http.uploadFile('/finance/importData', formData,
  916. res => {
  917. this.$refs.upload.clearFiles();
  918. this.listLoading = false;
  919. this.isUploading = false;
  920. if (res.code == "ok") {
  921. this.$message({
  922. message: "导入成功",
  923. type: "success"
  924. });
  925. this.importDialog = false;
  926. //重新读取列表
  927. this.getList();
  928. } else {
  929. this.$message({
  930. message: res.msg,
  931. type: "error"
  932. });
  933. }
  934. },
  935. error => {
  936. this.$refs.upload.clearFiles();
  937. this.listLoading = false;
  938. this.$message({
  939. message: error,
  940. type: "error"
  941. });
  942. });
  943. }
  944. },
  945. //获取项目列表
  946. getList() {
  947. this.listLoading = true;
  948. this.http.post('/finance/getByMonth', {
  949. companyId: this.user.companyId,
  950. yearMonth: this.date
  951. },
  952. res => {
  953. this.listLoading = false;
  954. if (res.code == "ok") {
  955. var list = res.data;
  956. this.allFinanceList = list;
  957. this.list = this.allFinanceList;
  958. this.noReportUserList = list.filter(r=>r.hasReport == 0);
  959. } else {
  960. this.$message({
  961. message: res.msg,
  962. type: "error"
  963. });
  964. }
  965. },
  966. error => {
  967. this.listLoading = false;
  968. this.$message({
  969. message: error,
  970. type: "error"
  971. });
  972. });
  973. },
  974. },
  975. created() {
  976. var d = new Date();
  977. this.date = d.getFullYear() +'-'+ ((d.getMonth()+1) < 10? '0'+(d.getMonth()+1):d.getMonth()+1);
  978. },
  979. mounted() {
  980. let height = window.innerHeight;
  981. this.tableHeight = height - 245;
  982. const that = this;
  983. window.onresize = function temp() {
  984. that.tableHeight = window.innerHeight - 245;
  985. };
  986. this.getCustomColumn();
  987. this.getList();
  988. // this.getProjects();
  989. this.addreviewer();
  990. this.arrter()
  991. },
  992. updated() {
  993. this.$nextTick(() => {
  994. this.$refs['table'].doLayout();
  995. })
  996. }
  997. };
  998. </script>
  999. <style lang="scss" scoped>
  1000. .nameList {
  1001. height: 400px;
  1002. overflow: auto;
  1003. }
  1004. </style>