소스 검색

feat: 信息价指数计算

zhangweicheng 3 년 전
부모
커밋
b4634bc4bf

+ 15 - 0
modules/all_models/std_price_info_index.js

@@ -0,0 +1,15 @@
+// 信息价类型
+const mongoose = require('mongoose');
+
+const Schema = mongoose.Schema;
+const priceInfoClass = new Schema({
+    ID: String,
+    code: String,//编码前4位
+    period: String, // 期数 eg: 2020-05
+    areaID: String,
+    compilationID: String, // 费用定额
+    index: Number//指数,保留两位小数
+}, {versionKey: false});
+priceInfoClass.index({ areaID:1});
+priceInfoClass.index({ period:1});
+mongoose.model('std_price_info_index', priceInfoClass, 'std_price_info_index');

+ 2 - 0
modules/all_models/std_price_info_items.js

@@ -83,4 +83,6 @@ const priceInfoItems = new Schema({
         default: []
     }
 }, { versionKey: false });
+priceInfoItems.index({ areaID:1,period:1});
+
 mongoose.model('std_price_info_items', priceInfoItems, 'std_price_info_items');

+ 12 - 0
modules/price_info_lib/controllers/index.js

@@ -217,6 +217,18 @@ class PriceInfoController extends BaseController {
         }
     }
 
+    async calcPriceIndex(req, res) {
+        try {
+            const { period, libID ,compilationID} = JSON.parse(req.body.data);
+            const areaID = '971fb9a0-0f93-11eb-b53c-45271c1df90f';//写死珠海地区
+            const data = await facade.calcPriceIndex(libID,period, areaID,compilationID);
+            res.json({ error: 0, message: 'getCLass success', data });
+        } catch (err) {
+            console.log(err);
+            res.json({ error: 1, message: err.toString() });
+        }
+    }
+
     async getPriceData(req, res) {
         try {
             const { classIDList } = JSON.parse(req.body.data);

+ 85 - 0
modules/price_info_lib/facade/index.js

@@ -1,5 +1,7 @@
 const mongoose = require('mongoose');
 const uuidV1 = require('uuid/v1');
+const _ = require('lodash');
+const scMathUtil = require('../../../public/scMathUtil').getUtil();
 const { CRAWL_LOG_KEY, ProcessStatus } = require('../../../public/constants/price_info_constant');
 
 const priceInfoLibModel = mongoose.model('std_price_info_lib');
@@ -8,6 +10,9 @@ const priceInfoItemModel = mongoose.model('std_price_info_items');
 const priceInfoAreaModel = mongoose.model('std_price_info_areas');
 const compilationModel = mongoose.model('compilation');
 const importLogsModel = mongoose.model('import_logs');
+const priceInfoIndexModel = mongoose.model('std_price_info_index');
+
+
 
 async function getLibs(query) {
     return await priceInfoLibModel.find(query).lean();
@@ -532,6 +537,85 @@ async function editClassData(updateData) {
     }
 }
 
+//计算指标平均值
+function calcIndexAvg (period, areaID,compilationID,preCodeMap){
+    const newData = []; 
+    for(const code in preCodeMap){
+        const indexArr = preCodeMap[code];
+        let total = 0;
+
+        for(const index of indexArr){
+            total  =   scMathUtil.roundForObj(total + index,2); 
+        }
+        const avg = scMathUtil.roundForObj(total/indexArr.length,2); 
+        newData.push({ID:uuidV1(),code,period,areaID,compilationID,index:avg})
+    }
+    return newData
+}
+
+//一个月里有classCode相同,但是价格不同的情况,取平均值
+function getClassCodePriceAvgMap  (items){
+    const classCodeMap = {};
+    for(const b of items){
+        classCodeMap[b.classCode]?classCodeMap[b.classCode].push(b):classCodeMap[b.classCode]=[b];
+    }
+
+    for(const classCode in classCodeMap){
+        const baseItems = classCodeMap[classCode];
+        const item = baseItems[0];
+        if(baseItems.length > 1){
+            let sum = 0;
+            for(const b of baseItems){
+                sum += parseFloat(b.noTaxPrice);       
+            }      
+            classCodeMap[classCode] = {code:item.code,name:item.name,price:scMathUtil.roundForObj(sum/baseItems.length,2)};
+        }else{
+            classCodeMap[classCode] = {code:item.code,name:item.name,price:parseFloat(item.noTaxPrice)}
+        }
+
+    }
+
+    return classCodeMap
+  
+}
+
+async function calcPriceIndex(libID,period, areaID,compilationID){
+    const baseItems = await priceInfoItemModel.find({areaID,period:'2022年-01月'}).lean();//以珠海 22年1月的数据为基准
+    const currentItems =  await priceInfoItemModel.find({areaID,period}).lean();
+    const preCodeMap = {};//编码前4位-指数映射
+    const baseAvgMap = getClassCodePriceAvgMap(baseItems);
+    const currentAvgMap = getClassCodePriceAvgMap(currentItems);
+    
+    let message = '';
+
+    for(const classCode in currentAvgMap){
+        const c = currentAvgMap[classCode];
+        const preCode = c.code.substr(0,4);
+        let index = 1;
+        const baseItem = baseAvgMap[classCode];
+        const tem = {index,classCode,name:c.name,code:c.code};
+        
+        if(baseItem && baseItem.price){//一个月份里有多个值时,先取平均再计算
+            index =  scMathUtil.roundForObj(c.price/baseItem.price,2);
+            tem.baseName = baseItem.name;
+        }
+        tem.index = index;
+        if(Math.abs(index - 1) > 0.2){
+            const string = `classCode:${tem.classCode},编号:${tem.code},基础名称:${tem.baseName},当前库中名称:${tem.name},指数:${tem.index};\n`;
+            message +=string;
+            console.log(string)
+        } 
+
+      preCodeMap[preCode]?preCodeMap[preCode].push(index):preCodeMap[preCode]=[index];
+    }
+    const newIndexData = calcIndexAvg(period, areaID,compilationID,preCodeMap)
+    //删除旧数据
+    await priceInfoIndexModel.deleteMany({areaID,period});
+    //插入新数据
+    await priceInfoIndexModel.insertMany(newIndexData);
+    return message;
+}
+
 module.exports = {
     getLibs,
     createLib,
@@ -546,6 +630,7 @@ module.exports = {
     insertAreas,
     deleteAreas,
     getClassData,
+    calcPriceIndex,
     getPriceData,
     editPriceData,
     editClassData

+ 1 - 0
modules/price_info_lib/routes/index.js

@@ -21,6 +21,7 @@ module.exports = function (app) {
     router.post("/insertArea", priceInfoController.auth, priceInfoController.init, priceInfoController.insertArea);
     router.post("/deleteArea", priceInfoController.auth, priceInfoController.init, priceInfoController.deleteArea);
     router.post("/getClassData", priceInfoController.auth, priceInfoController.init, priceInfoController.getClassData);
+    router.post("/calcPriceIndex", priceInfoController.auth, priceInfoController.init, priceInfoController.calcPriceIndex);
     router.post("/getPriceData", priceInfoController.auth, priceInfoController.init, priceInfoController.getPriceData);
     router.post("/editPriceData", priceInfoController.auth, priceInfoController.init, priceInfoController.editPriceData);
     router.post("/editClassData", priceInfoController.auth, priceInfoController.init, priceInfoController.editClassData);

+ 29 - 1
web/maintain/price_info_lib/html/edit.html

@@ -18,7 +18,10 @@
         <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
             <span class="header-logo px-2">Smartcost</span>
             <div class="navbar-text"><a href="/priceInfo/main">信息价库</a><i
-                    class="fa fa-angle-right fa-fw"></i><%= libName  %></div>
+                    class="fa fa-angle-right fa-fw"></i><%= libName  %>
+               <button id="calc-price-index">计算指数</button>     
+            </div>
+
         </nav>
     </div>
     <div class="wrapper">
@@ -55,6 +58,31 @@
             </div>
         </div>
     </div>
+
+
+    <div class="modal fade in" id="result-info" data-backdrop="static">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content" style=" width: 900px;">
+                <div class="modal-header">
+                    <h5 class="modal-title">结果确认</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body"  >
+                    <div class="form-group">
+                        <div>以下指数偏差较大,请确认:</div>
+                        <div id="result-info-body">
+                         
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer" style="justify-content: center">
+                    <button type="button" class="btn btn-primary" data-dismiss="modal" id="copy-lib-confirm">确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- JS. -->
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>

+ 31 - 0
web/maintain/price_info_lib/js/index.js

@@ -322,6 +322,7 @@ const CLASS_BOOK = (() => {
     const $downLevel = $('#tree-down-level');
     const $downMove = $('#tree-down-move');
     const $upMove = $('#tree-up-move');
+    const $calcPriceIndex = $('#calc-price-index');
 
     // 插入
     let canInsert = true;
@@ -640,6 +641,31 @@ const CLASS_BOOK = (() => {
     }, DEBOUNCE_TIME, { leading: true });
     sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
 
+
+
+    $calcPriceIndex.click(_.debounce(async()=>{
+        $.bootstrapLoading.start();
+        try {
+        const data = await ajaxPost('/priceInfo/calcPriceIndex', { libID, period:curLibPeriod,compilationID }, TIME_OUT);
+          //alert(data);
+          
+          if(data){
+              const htmlStr = data.replace(/\n/gm,'<br>'); //replaceAll('\n','<br>',data);
+              $("#result-info-body").html(htmlStr);
+              $("#result-info").modal('show');
+          }else{
+              alert('计算完成!')
+          }  
+
+
+        } catch (error) {
+            console.log(error);
+        }
+        $.bootstrapLoading.end();
+
+    }, DEBOUNCE_TIME, { leading: true }));
+
+
     return {
         initData,
         handleSelectionChanged,
@@ -712,6 +738,7 @@ const PRICE_BOOK = (() => {
         $.bootstrapLoading.start();
         try {
             cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, TIME_OUT);
+            cache = _.sortBy(cache,'classCode');
             showData(sheet, cache, setting.header, 5);
             const row = sheet.getActiveRowIndex();
             const keywordList = cache[row] && cache[row].keywordList || [];
@@ -847,4 +874,8 @@ $(document).ready(() => {
     AREA_BOOK.handleSelectionChanged(0);
     const $range = $(document.body);
     lockUtil.lockTools($range, locked);
+
+
+
+
 });