CostBaseline.vue 21 KB

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