CostBaseline.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. <template>
  2. <div :style="'padding:10px;background:#f7f7f7;min-height:'+tableHeight+'px;'">
  3. <div style="margin: 0 auto;width:1000px;">
  4. <el-row :gutter="24">
  5. <el-col :span="12">
  6. <div class="box" ref="allBox">
  7. <div >
  8. <!-- <div class="lableTxt">总成本基线</div> -->
  9. <label class="lableTxt">{{ $t('totalcostbaseline') }}<el-link v-if="permissions.projectCorrection" @click="correctBase" style="float:right;"><i class="el-icon-edit" ></i></el-link></label>
  10. <div class="lableCon" v-for="item in projectBaseCostData" :key="item.id">
  11. <div><span class="gray_label">{{item.baseName}}:</span></div>
  12. <div><span style="float:right;">¥{{item.baseAmount | numberToCurrency}}</span></div>
  13. <div>
  14. <span style="float:right;">{{ $t('restcanbedialed') }} <span :style="item.baseAmount * 0.9 < baseCostFilter(item.baseId) ? 'color:red;' : ''">¥{{(item.baseAmount - baseCostFilter(item.baseId)) | numberToCurrency}}</span></span>
  15. </div>
  16. </div>
  17. <div style="height:24px">
  18. <el-link style="float:right;margin-right:10px" @click="addCostAdd" size="small" v-if="permissions.projectAllocate" type="primary">{{ $t('allocatethecostbudget') }}</el-link>
  19. </div>
  20. </div>
  21. </div>
  22. </el-col>
  23. <el-col :span="12">
  24. <div class="box" ref="nowBox" :style="'height:' + nowBaseHeight + 'px;'">
  25. <label class="lableTxt">{{ $t('currentcostbaseline') }}</label>
  26. <div class="lableCon" v-for="item in nowBaseList" :key="item.id">
  27. <div><span class="gray_label">{{item.baseName}}:</span></div>
  28. <div><span style="float:right;">¥{{item.baseAmount==null?'-':item.baseAmount | numberToCurrency}}</span></div>
  29. <div class="nowBase_div3">
  30. <span style="float:right;">{{ $t('yi') }}<span>¥{{item.realCost | numberToCurrency}}</span></span>
  31. </div>
  32. <div class="nowBase_div4">
  33. <span style="float:right;">{{ $t('yu') }}<span :style="item.baseAmount * 0.9 < item.realCost ? 'color:red;' : ''">¥{{(item.baseAmount - item.realCost) | numberToCurrency}}</span></span>
  34. </div>
  35. </div>
  36. <div style="height:24px">
  37. <!-- <el-link style="float:right;margin-right:10px" @click="addCostAdd" size="small" v-if="permissions.projectAllocate" type="primary">下拨成本预算</el-link> -->
  38. </div>
  39. </div>
  40. </el-col>
  41. <el-col :span="24"></el-col>
  42. </el-row>
  43. <el-row :gutter="24">
  44. <el-col :span="24">
  45. <div class="box">
  46. <el-table :data="addList" :loading="ListLoading" :default-sort="{prop:'indate',order:'descending'}">
  47. <el-table-column v-for="item in addListColumns" :key="item.id" :label="item.name" align="right" header-align="center" min-width="150">
  48. <template slot-scope="scope">
  49. <span style="margin-right: 40px;">¥{{itemListFilter(scope.row.addItemList,item.id) | numberToCurrency}}</span>
  50. </template>
  51. </el-table-column>
  52. <el-table-column :label="$t('xiabo')" prop="indate" align="center" min-width="200"></el-table-column>
  53. <el-table-column :label="$t('caozuo')" prop="userName" align="center" min-width="120">
  54. <template slot-scope="scope">
  55. <div>
  56. <span v-if="user.userNameNeedTranslate != 1">
  57. {{scope.row.userName}}
  58. </span>
  59. <span v-if="user.userNameNeedTranslate == 1">
  60. <ww-open-data type='userName' :openid='scope.row.userName'></ww-open-data>
  61. </span>
  62. </div>
  63. </template>
  64. </el-table-column>
  65. <el-table-column :label="$t('bei-zhu')" prop="remark" align="left" header-align="left" show-overflow-tooltip min-width="200"></el-table-column>
  66. <el-table-column label="" align="center" fixed="right" v-if="permissions.projectAllocate">
  67. <template slot-scope="scope">
  68. <el-button size="small" @click="revert(scope.row.id)" v-if="scope.$index == 0">{{ $t('btn.undo') }}</el-button>
  69. </template>
  70. </el-table-column>
  71. </el-table>
  72. </div>
  73. </el-col>
  74. </el-row>
  75. </div>
  76. <el-dialog :title="$t('allocatethecostbudget')" v-if="addCostAddDialog" :visible.sync="addCostAddDialog" :close-on-click-modal="false" width="600px">
  77. <el-form>
  78. <el-form-item v-for="item,index in modBaseCostData" :key="item.id" :label="item.baseName" label-width="150px">
  79. <el-input :id="'nowBaseCost'+index" v-model="item.baseAmount" :placeholder="$t('peaseenterthe')" clearable @keyup.native="restrictNumber('nowBaseCost'+index)" style="width:350px"></el-input>
  80. </el-form-item>
  81. <el-form-item :label="$t('bei-zhu')" label-width="150px">
  82. <el-input v-model="remark" :placeholder="$t('peaseenterthe')" style="width:350px"></el-input>
  83. </el-form-item>
  84. </el-form>
  85. <div slot="footer" class="dialog-footer">
  86. <!-- <el-button @click="test">test</el-button> -->
  87. <el-button @click.native="addCostAddDialog = false">{{ $t('btn.cancel') }}</el-button>
  88. <el-button type="primary" @click="addCostAddSure" :loading="addLoading">{{ $t('btn.submit') }}</el-button>
  89. </div>
  90. </el-dialog>
  91. <el-dialog :title="$t('jiaoyan')" v-if="correctBaseDialog" :visible.sync="correctBaseDialog" :close-on-click-modal="false" width="600px">
  92. <el-form>
  93. <el-form-item v-for="item,index in correctBaseCostData" :key="item.id" :label="item.baseName" label-width="150px">
  94. <el-input :id="'baseCost'+index" v-model="item.baseAmount" :placeholder="$t('peaseenterthe')" clearable @keyup.native="restrictNumber('baseCost'+index)" style="width:350px"></el-input>
  95. </el-form-item>
  96. <el-form-item :label="$t('bei-zhu')" label-width="150px">
  97. <el-input v-model="remark" :placeholder="$t('reasoforcorrection')" style="width:350px"></el-input>
  98. </el-form-item>
  99. </el-form>
  100. <div slot="footer" class="dialog-footer">
  101. <!-- <el-button @click="test">test</el-button> -->
  102. <el-button @click.native="correctBaseDialog = false">{{ $t('btn.cancel') }}</el-button>
  103. <el-button type="primary" @click="correctBaseSure" :loading="addLoading">{{ $t('btn.submit') }}</el-button>
  104. </div>
  105. </el-dialog>
  106. </div>
  107. </template>
  108. <script>
  109. import util from "../../common/js/util";
  110. export default {
  111. data() {
  112. return {
  113. user: JSON.parse(sessionStorage.getItem('user')),
  114. permissions: JSON.parse(sessionStorage.getItem("permissions")),
  115. curProjectId: null,
  116. addLoading: false,
  117. projectBaseCostData: [],
  118. modBaseCostData: [],
  119. correctBaseCostData: [],
  120. remark: '',
  121. addCostAddDialog: false,
  122. addListColumns:[],
  123. ListLoading: false,
  124. nowBaseList: [],
  125. correctBaseDialog: false,
  126. projectContractAmount: null,
  127. nowBaseHeight: ''
  128. };
  129. },
  130. filters: {
  131. numberToCurrency(value) {
  132. // console.log('info numberToCurrency='+value);
  133. if (!value || value=='-') return '0.00'
  134. value = value.toFixed(2)
  135. const intPart = Math.trunc(value)
  136. const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
  137. let floatPart = '.00'
  138. const valueArray = value.toString().split('.')
  139. if (valueArray.length === 2) { // 有小数部分
  140. floatPart = valueArray[1].toString() // 取得小数部分
  141. return intPartFormat + '.' + floatPart
  142. }
  143. return intPartFormat + floatPart
  144. }
  145. },
  146. methods: {
  147. restrictNumber(targetId) {
  148. let inpu = document.getElementById(targetId);
  149. inpu.value = inpu.value.replace(/[^\d.]/g, ""); //仅保留数字和"."
  150. inpu.value = inpu.value.replace(/\.{2,}/g, "."); //两个连续的"."仅保留第一个"."
  151. inpu.value = inpu.value.replace(".", "$#*").replace(/\./g,'').replace('$#*','.');//去除其他"."
  152. inpu.value = inpu.value.replace(/^(\d+)\.(\d\d).*$/, '$1.$2');;//限制只能输入两个小数
  153. if (inpu.value.indexOf(".") < 0 && inpu.value != "") { //首位是0的话去掉
  154. inpu.value = parseFloat(inpu.value);
  155. }
  156. },
  157. test(item){
  158. // let list = [
  159. // {id: 5, name: 'zs'},
  160. // {id: 6, name: 'ls'},
  161. // {id: 7, name: 'ww'}
  162. // ]
  163. // let lid = 5
  164. // let item = this.itemListFilter(list,lid)
  165. // console.log('test',this.addListColumns);
  166. },
  167. baseCostFilter(eId){
  168. let emItem = this.nowBaseList.filter((em)=>{
  169. return em.baseId == eId
  170. })
  171. if(emItem.length == 0){
  172. return 0
  173. }else{
  174. return emItem[0].baseAmount
  175. }
  176. },
  177. itemListFilter(emList,eId){
  178. let emItem = emList.filter((em)=>{
  179. return em.baseId == eId
  180. })
  181. if(emItem.length == 0){
  182. return 0
  183. }else{
  184. return emItem[0].baseAmount
  185. }
  186. },
  187. getProjectBaseData(projectId) {
  188. this.http.post('/project-basecost/get',{
  189. projectId: projectId
  190. },res => {
  191. if (res.code == "ok") {
  192. this.projectBaseCostData = res.data;
  193. } else {
  194. this.$message({
  195. message: res.msg,
  196. type: "error"
  197. });
  198. }
  199. },error => {
  200. this.$message({
  201. message: error,
  202. type: "error"
  203. });
  204. });
  205. },
  206. // 撤销操作
  207. revert(eId){
  208. this.http.post('/project-addcost-record/revert',{
  209. id: eId
  210. },res => {
  211. if(res.code == 'ok'){
  212. this.$message({
  213. message: this.$t('Revocationofsuccess'),
  214. type: 'success'
  215. })
  216. this.getAddList()
  217. this.getNowBase()
  218. }else {
  219. this.$message({
  220. message: res.msg,
  221. type: 'error'
  222. })
  223. }
  224. },err => {
  225. this.$message({
  226. message: err,
  227. type: 'error'
  228. })
  229. })
  230. },
  231. correctBase(){
  232. // 校正成本基线
  233. this.correctBaseCostData = JSON.parse(JSON.stringify(this.projectBaseCostData))
  234. this.correctBaseDialog = true
  235. },
  236. addCostAdd(){
  237. this.modBaseCostData = JSON.parse(JSON.stringify(this.projectBaseCostData))
  238. for (let i = 0; i < this.modBaseCostData.length; i++) {
  239. this.modBaseCostData[i].baseAmount = 0
  240. }
  241. this.addCostAddDialog = true
  242. },
  243. addCostAddSure(){
  244. this.addLoading = true
  245. let itemList = []
  246. let isAll0 = true
  247. for(let i=0; i<this.modBaseCostData.length; i++){
  248. // let itemListItem = {
  249. // baseId: this.modBaseCostData[i].baseId,
  250. // baseName: this.modBaseCostData[i].baseName,
  251. // baseAmount: this.modBaseCostData[i].baseAmount
  252. // }
  253. if(this.modBaseCostData[i].baseAmount != 0){
  254. isAll0 = false
  255. }
  256. itemList.push({
  257. baseId: this.modBaseCostData[i].baseId,
  258. baseName: this.modBaseCostData[i].baseName,
  259. baseAmount: this.modBaseCostData[i].baseAmount
  260. })
  261. }
  262. if(isAll0){
  263. this.$message({
  264. message: this.$t('saoyixiang'),
  265. type: 'warning'
  266. })
  267. this.addLoading = false
  268. return
  269. }
  270. this.http.post('/project-addcost-record/add',{
  271. projectId: this.curProjectId,
  272. userId: this.user.id,
  273. userName: this.user.name,
  274. itemList: JSON.stringify(itemList),
  275. remark: this.remark
  276. },res => {
  277. if(res.code == 'ok'){
  278. this.addLoading = false
  279. this.addCostAddDialog = false
  280. this.$message({
  281. message: this.$t('xiabochenggong'),
  282. type: 'success'
  283. })
  284. this.remark = ''
  285. this.getAddList()
  286. this.getNowBase()
  287. }else {
  288. this.addLoading = false
  289. this.$message({
  290. message: res.msg,
  291. type: 'error'
  292. })
  293. }
  294. },err => {
  295. this.addLoading = false
  296. this.$message({
  297. message: err,
  298. type: 'error'
  299. })
  300. })
  301. },
  302. correctBaseSure(){
  303. //如果没有做修改,不提交数据
  304. var hasChangeData = false;
  305. for (var i=0;i<this.correctBaseCostData.length; i++) {
  306. var item = this.correctBaseCostData[i];
  307. var oldAmount = this.projectBaseCostData.filter(p=>p.id == item.id)[0].baseAmount;
  308. if (item.baseAmount != oldAmount) {
  309. hasChangeData = true;
  310. break;
  311. }
  312. }
  313. if (!hasChangeData) {
  314. this.correctBaseDialog = false;
  315. return;
  316. }
  317. this.http.post('/project/adjustBase', {
  318. id: this.curProjectId,
  319. contractAmount: this.projectContractAmount,
  320. baseCostData:JSON.stringify(this.correctBaseCostData),
  321. remark: this.remark
  322. },
  323. res => {
  324. if (res.code == "ok") {
  325. this.correctBaseDialog = false;
  326. this.$message({
  327. message: this.$t('jiaozheng'),
  328. type: "success"
  329. });
  330. this.remark = ''
  331. this.getProjectBaseData(this.curProjectId)
  332. } else {
  333. this.$message({
  334. message: res.msg,
  335. type: "error"
  336. });
  337. }
  338. },
  339. error => {
  340. this.$message({
  341. message: error,
  342. type: "error"
  343. });
  344. });
  345. },
  346. getNowBase(){
  347. this.http.post('/project-currentcost/get',{
  348. companyId: this.user.companyId,
  349. projectId: this.curProjectId
  350. },res => {
  351. if(res.code == 'ok'){
  352. this.nowBaseList = res.data
  353. // if(res.data.length == 0){
  354. this.getBoxHeight()
  355. // let allboxh = this.$refs.allBox.scrollHeight - 20
  356. // console.log('getnowbase',allboxh);
  357. // this.nowBaseHeight = allboxh
  358. // }
  359. }else {
  360. this.$message({
  361. message: res.msg,
  362. type: 'error'
  363. })
  364. }
  365. },err => {
  366. this.$message({
  367. message: err,
  368. type: 'error'
  369. })
  370. })
  371. },
  372. getAddList(){
  373. this.ListLoading = true
  374. this.http.post('/project-addcost-record/getAddList',{
  375. companyId: this.user.companyId,
  376. projectId: this.curProjectId
  377. },res => {
  378. if(res.code == 'ok'){
  379. this.ListLoading = false
  380. this.addList = res.data.recordList
  381. this.addListColumns = res.data.columns
  382. // console.log('getaddlist',res.data);
  383. }else {
  384. this.ListLoading = false
  385. this.$message({
  386. message: res.msg,
  387. type: 'error'
  388. })
  389. }
  390. },err => {
  391. this.ListLoading = false
  392. this.$message({
  393. message: err,
  394. type: 'error'
  395. })
  396. })
  397. },
  398. getProjectInfo() {
  399. this.http.post('/project/detail', {
  400. id: this.curProjectId
  401. },
  402. res => {
  403. if (res.code == "ok") {
  404. this.projectContractAmount = res.data.contractAmount;
  405. // console.log('res.data',res.data);
  406. } else {
  407. this.$message({
  408. message: res.msg,
  409. type: "error"
  410. });
  411. }
  412. },
  413. error => {
  414. this.$message({
  415. message: error,
  416. type: "error"
  417. });
  418. });
  419. },
  420. refreshPage(){
  421. this.curProjectId = parseInt(this.$route.params.id);
  422. this.getProjectBaseData(this.curProjectId)
  423. this.getAddList()
  424. this.getNowBase()
  425. this.getProjectInfo()
  426. },
  427. getBoxHeight(){
  428. let allboxh = this.$refs.allBox.scrollHeight - 20
  429. this.nowBaseHeight = allboxh
  430. }
  431. },
  432. created() {
  433. let height = window.innerHeight;
  434. this.tableHeight = height - 160;
  435. const that = this;
  436. window.onresize = function temp() {
  437. that.tableHeight = window.innerHeight - 160;
  438. };
  439. },
  440. mounted() {
  441. this.curProjectId = parseInt(this.$route.params.id);
  442. // var _this = this;
  443. // var that = this
  444. // console.log("mounted")
  445. // window.addEventListener("resize", function() {
  446. // // _this.profitChart.resize();
  447. // // that.profitChart.resize();
  448. // });
  449. this.getProjectBaseData(this.curProjectId)
  450. this.getAddList()
  451. this.getNowBase()
  452. this.getProjectInfo()
  453. }
  454. };
  455. </script>
  456. <style scoped>
  457. .box {
  458. background:#fff;
  459. border: 1px solid #eeeeee;
  460. border-radius:5px;
  461. padding:10px;
  462. margin-top:10px;
  463. overflow-x: auto;
  464. }
  465. .el-row {
  466. margin-top:10px;
  467. }
  468. .lableTxt {
  469. color:#666;
  470. }
  471. .lableCon{
  472. margin: 20px 10px;
  473. height: 20px;
  474. }
  475. .lableCon div:nth-child(1){
  476. width: 30%;
  477. float: left;
  478. }
  479. .lableCon div:nth-child(2){
  480. width: 20%;
  481. float: left;
  482. }
  483. .lableCon div:nth-child(3){
  484. width: 50%;
  485. float: left;
  486. font-size: 13px;
  487. color: #999;
  488. line-height: 20px;
  489. }
  490. .lableCon .nowBase_div3{
  491. width: 25% !important;
  492. float: left;
  493. font-size: 13px;
  494. color: #999;
  495. line-height: 20px;
  496. }
  497. .lableCon .nowBase_div4{
  498. width: 25%;
  499. float: left;
  500. font-size: 13px;
  501. color: #999;
  502. line-height: 20px;
  503. }
  504. .gray_label {
  505. color: #999;
  506. }
  507. </style>