wu 1 hete
szülő
commit
2c203c1ea1

+ 20 - 0
src/custom/restcontroller/R.java

@@ -7678,6 +7678,26 @@ public class R {
         public static class v1 {
         }
     }
+
+    public static class ID2025122611124202 {
+        public static class v1 {
+        }
+    }
+
+    public static class ID2025122611132802 {
+        public static class v1 {
+        }
+    }
+
+    public static class ID2025122611135102 {
+        public static class v1 {
+        }
+    }
+
+    public static class ID2025122714510802 {
+        public static class v1 {
+        }
+    }
 }
 
 

+ 21 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/依人员统计目标.sql

@@ -0,0 +1,21 @@
+SELECT t4.sa_saleareaid,
+       sum(ROUND(m1 * price, 2))  m1amount,
+       sum(ROUND(m2 * price, 2))  m2amount,
+       sum(ROUND(m3 * price, 2))  m3amount,
+       sum(ROUND(m4 * price, 2))  m4amount,
+       sum(ROUND(m5 * price, 2))  m5amount,
+       sum(ROUND(m6 * price, 2))  m6amount,
+       sum(ROUND(m7 * price, 2))  m7amount,
+       sum(ROUND(m8 * price, 2))  m8amount,
+       sum(ROUND(m9 * price, 2))  m9amount,
+       sum(ROUND(m10 * price, 2)) m10amount,
+       sum(ROUND(m11 * price, 2)) m11amount,
+       sum(ROUND(m12 * price, 2)) m12amount
+from sa_salestargetbill t1
+         INNER JOIN sa_salestarget t2 ON t2.sa_salestargetbillid = t1.sa_salestargetbillid
+         INNER JOIN sys_hr t3 on t3.userid = t1.createuserid
+         INNER JOIN sa_salearea_hr t4 ON t4.hrid = t3.hrid
+WHERE t1.year = $year$
+  and t1.`status` = '审核'
+  and t1.siteid = $siteid$
+GROUP BY t4.sa_saleareaid

+ 6 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/依人员统计订单.sql

@@ -0,0 +1,6 @@
+SELECT t3.sa_saleareaid, sum(t2.amount) amount, DATE_FORMAT(t1.checkdate, '%Y-%m') ym
+from sa_order t1
+         INNER JOIN sa_orderitems t2 ON t2.sa_orderid = t1.sa_orderid and t2.siteid = t1.siteid
+         INNER JOIN sa_salearea_hr t3 ON t3.hrid = t1.saler_hrid
+WHERE t1.siteid = $siteid$ and t1.`status` in ('审核', '关闭') and YEAR (t1.checkdate) in ($year$, $befyear$)
+GROUP BY t3.sa_saleareaid, ym

+ 21 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/依医院统计目标.sql

@@ -0,0 +1,21 @@
+SELECT t3.sa_saleareaid,
+       sum(ROUND(m1 * price, 2))  m1amount,
+       sum(ROUND(m2 * price, 2))  m2amount,
+       sum(ROUND(m3 * price, 2))  m3amount,
+       sum(ROUND(m4 * price, 2))  m4amount,
+       sum(ROUND(m5 * price, 2))  m5amount,
+       sum(ROUND(m6 * price, 2))  m6amount,
+       sum(ROUND(m7 * price, 2))  m7amount,
+       sum(ROUND(m8 * price, 2))  m8amount,
+       sum(ROUND(m9 * price, 2))  m9amount,
+       sum(ROUND(m10 * price, 2)) m10amount,
+       sum(ROUND(m11 * price, 2)) m11amount,
+       sum(ROUND(m12 * price, 2)) m12amount
+from sa_salestargetbill t1
+         INNER JOIN sa_salestarget t2 ON t2.sa_salestargetbillid = t1.sa_salestargetbillid
+         INNER JOIN sa_customers t3 on t3.sa_customersid=t1.sa_customersid
+WHERE t1.year = $year$
+  and t1.`status` = '审核'
+  and t1.siteid = $siteid$
+  and t1.sa_customersid>0
+GROUP BY t3.sa_saleareaid

+ 6 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/依医院统计订单.sql

@@ -0,0 +1,6 @@
+SELECT t3.sa_saleareaid, sum(t2.amount) amount, DATE_FORMAT(t1.checkdate, '%Y-%m') ym
+from sa_order t1
+         INNER JOIN sa_orderitems t2 ON t2.sa_orderid = t1.sa_orderid and t2.siteid = t1.siteid
+         INNER JOIN sa_customers t3 on t3.sa_customersid=t1.sa_customersid
+WHERE t1.siteid = $siteid$ and t1.`status` in ('审核', '关闭') and YEAR (t1.checkdate) in ($year$, $befyear$) and t1.sa_customersid>0
+GROUP BY t3.sa_saleareaid, ym

+ 22 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/依经销商统计目标.sql

@@ -0,0 +1,22 @@
+SELECT
+    t4.sa_saleareaid,
+    sum(ROUND(m1*price,2)) m1amount,
+    sum(ROUND(m2*price,2)) m2amount,
+    sum(ROUND(m3*price,2)) m3amount,
+    sum(ROUND(m4*price,2)) m4amount,
+    sum(ROUND(m5*price,2)) m5amount,
+    sum(ROUND(m6*price,2)) m6amount,
+    sum(ROUND(m7*price,2)) m7amount,
+    sum(ROUND(m8*price,2)) m8amount,
+    sum(ROUND(m9*price,2)) m9amount,
+    sum(ROUND(m10*price,2)) m10amount,
+    sum(ROUND(m11*price,2)) m11amount,
+    sum(ROUND(m12*price,2)) m12amount
+from sa_salestargetbill t1
+         INNER JOIN sa_salestarget t2 ON t2.sa_salestargetbillid=t1.sa_salestargetbillid
+         INNER JOIN sa_agents_hospital t3 on t3.sa_hospitaldepid=t2.sa_hospitaldepid
+         INNER JOIN sys_enterprise_tradefield t4 ON t4.sa_agentsid=t3.sa_agentsid
+WHERE t1.year = $year$
+  and t1.`status` = '审核'
+  and t1.siteid = $siteid$
+GROUP BY t4.sa_saleareaid

+ 6 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/依经销商统计订单.sql

@@ -0,0 +1,6 @@
+SELECT t3.sa_saleareaid, sum(t2.amount) amount, DATE_FORMAT(t1.checkdate, '%Y-%m') ym
+from sa_order t1
+         INNER JOIN sa_orderitems t2 ON t2.sa_orderid = t1.sa_orderid and t2.siteid = t1.siteid
+         INNER JOIN sys_enterprise_tradefield t3 ON t3.sa_agentsid=t1.sa_agentsid
+WHERE t1.siteid = $siteid$ and t1.`status` in ('审核', '关闭') and YEAR (t1.checkdate) in ($year$, $befyear$) and t1.sa_agentsid>0
+GROUP BY t3.sa_saleareaid, ym

+ 19 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/按人员分组统计目标.sql

@@ -0,0 +1,19 @@
+SELECT t1.createuserid userid,
+       sum(ROUND(m1 * price, 2))  m1amount,
+       sum(ROUND(m2 * price, 2))  m2amount,
+       sum(ROUND(m3 * price, 2))  m3amount,
+       sum(ROUND(m4 * price, 2))  m4amount,
+       sum(ROUND(m5 * price, 2))  m5amount,
+       sum(ROUND(m6 * price, 2))  m6amount,
+       sum(ROUND(m7 * price, 2))  m7amount,
+       sum(ROUND(m8 * price, 2))  m8amount,
+       sum(ROUND(m9 * price, 2))  m9amount,
+       sum(ROUND(m10 * price, 2)) m10amount,
+       sum(ROUND(m11 * price, 2)) m11amount,
+       sum(ROUND(m12 * price, 2)) m12amount
+from sa_salestargetbill t1
+         INNER JOIN sa_salestarget t2 ON t2.sa_salestargetbillid = t1.sa_salestargetbillid
+WHERE t1.year =$year$
+  and t1.`status` = '审核'
+  and t1.siteid = $siteid$
+GROUP BY t1.createuserid

+ 6 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/按人员分组统计订单.sql

@@ -0,0 +1,6 @@
+SELECT t3.userid, sum(t2.amount) amount, DATE_FORMAT(t1.checkdate, '%Y-%m') ym
+from sa_order t1
+         INNER JOIN sa_orderitems t2 ON t2.sa_orderid = t1.sa_orderid and t2.siteid = t1.siteid
+         INNER JOIN sys_hr t3 ON t3.hrid = t1.saler_hrid
+WHERE t1.siteid = $siteid$ and t1.`status` in ('审核', '关闭') and YEAR (t1.checkdate) in ($year$, $befyear$)
+GROUP BY t3.userid, ym

+ 23 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/按医院分组统计目标.sql

@@ -0,0 +1,23 @@
+SELECT t3.sa_customersid,
+       t4.enterprisename hospitalname,
+       sum(ROUND(m1 * price, 2))  m1amount,
+       sum(ROUND(m2 * price, 2))  m2amount,
+       sum(ROUND(m3 * price, 2))  m3amount,
+       sum(ROUND(m4 * price, 2))  m4amount,
+       sum(ROUND(m5 * price, 2))  m5amount,
+       sum(ROUND(m6 * price, 2))  m6amount,
+       sum(ROUND(m7 * price, 2))  m7amount,
+       sum(ROUND(m8 * price, 2))  m8amount,
+       sum(ROUND(m9 * price, 2))  m9amount,
+       sum(ROUND(m10 * price, 2)) m10amount,
+       sum(ROUND(m11 * price, 2)) m11amount,
+       sum(ROUND(m12 * price, 2)) m12amount
+from sa_salestargetbill t1
+         INNER JOIN sa_salestarget t2 ON t2.sa_salestargetbillid = t1.sa_salestargetbillid
+         INNER JOIN sa_customers t3 on t3.sa_customersid=t1.sa_customersid
+         INNER JOIN sys_enterprise t4 ON t4.sys_enterpriseid=t3.sys_enterpriseid
+WHERE t1.year =$year$
+  and t1.`status` = '审核'
+  and t1.siteid = $siteid$
+  and t1.sa_customersid>0
+GROUP BY t3.sa_customersid

+ 10 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/按医院分组统计订单.sql

@@ -0,0 +1,10 @@
+SELECT t3.sa_customersid,
+       t4.enterprisename hospitalname,
+       sum(t2.amount) amount,
+       DATE_FORMAT(t1.checkdate, '%Y-%m') ym
+from sa_order t1
+         INNER JOIN sa_orderitems t2 ON t2.sa_orderid = t1.sa_orderid and t2.siteid = t1.siteid
+         INNER JOIN sa_customers t3 on t3.sa_customersid=t1.sa_customersid
+         INNER JOIN sys_enterprise t4 ON t4.sys_enterpriseid=t3.sys_enterpriseid
+WHERE t1.siteid = $siteid$ and t1.`status` in ('审核', '关闭') and YEAR (t1.checkdate) in ($year$, $befyear$) and t1.sa_customersid>0
+GROUP BY t3.sa_customersid, ym

+ 22 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/按经销商分组统计目标.sql

@@ -0,0 +1,22 @@
+SELECT
+    t4.sa_agentsid,
+    sum(ROUND(m1*price,2)) m1amount,
+    sum(ROUND(m2*price,2)) m2amount,
+    sum(ROUND(m3*price,2)) m3amount,
+    sum(ROUND(m4*price,2)) m4amount,
+    sum(ROUND(m5*price,2)) m5amount,
+    sum(ROUND(m6*price,2)) m6amount,
+    sum(ROUND(m7*price,2)) m7amount,
+    sum(ROUND(m8*price,2)) m8amount,
+    sum(ROUND(m9*price,2)) m9amount,
+    sum(ROUND(m10*price,2)) m10amount,
+    sum(ROUND(m11*price,2)) m11amount,
+    sum(ROUND(m12*price,2)) m12amount
+from sa_salestargetbill t1
+         INNER JOIN sa_salestarget t2 ON t2.sa_salestargetbillid=t1.sa_salestargetbillid
+         INNER JOIN sa_agents_hospital t3 on t3.sa_hospitaldepid=t2.sa_hospitaldepid
+         INNER JOIN sys_enterprise_tradefield t4 ON t4.sa_agentsid=t3.sa_agentsid
+WHERE t1.year = $year$
+  and t1.`status` = '审核'
+  and t1.siteid = $siteid$
+GROUP BY t4.sa_agentsid

+ 6 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/SQL/按经销商分组统计订单.sql

@@ -0,0 +1,6 @@
+SELECT t3.sa_agentsid, sum(t2.amount) amount, DATE_FORMAT(t1.checkdate, '%Y-%m') ym
+from sa_order t1
+         INNER JOIN sa_orderitems t2 ON t2.sa_orderid = t1.sa_orderid and t2.siteid = t1.siteid
+         INNER JOIN sys_enterprise_tradefield t3 ON t3.sa_agentsid=t1.sa_agentsid
+WHERE t1.siteid = $siteid$ and t1.`status` in ('审核', '关闭') and YEAR (t1.checkdate) in ($year$, $befyear$) and t1.sa_agentsid>0
+GROUP BY t3.sa_agentsid, ym

+ 463 - 0
src/custom/restcontroller/webmanage/sale/salestarget2/salestargetstatistics.java

@@ -0,0 +1,463 @@
+package restcontroller.webmanage.sale.salestarget2;
+
+import com.alibaba.fastjson.JSONObject;
+import common.Controller;
+import common.YosException;
+import common.annotation.API;
+import common.data.*;
+import restcontroller.R;
+
+import java.math.BigDecimal;
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.IsoFields;
+import java.util.ArrayList;
+
+public class salestargetstatistics extends Controller {
+    /**
+     * 构造函数
+     *
+     * @param content
+     */
+    public salestargetstatistics(JSONObject content) throws YosException {
+        super(content);
+    }
+
+    @API(title = "营销目标", apiversion = R.ID2025122611124202.v1.class)
+    public String marketingTarget() throws YosException {
+        int type = content.getIntValue("type", 1);
+        int year = content.getIntValue("year");
+        int befyear = year - 1;
+        int month = content.getIntValue("month");
+        String currentMonth = year + "-" + (month > 9 ? month : "0" + month);
+
+        Rows arearows = dbConnect.runSqlQuery("SELECT t1.* FROM view_areas t1 WHERE t1.siteid='" + siteid + "' ORDER BY t1.parentid,t1.sa_saleareaid");
+
+        ArrayList<String> saleareaids = arearows.toArrayList("sa_saleareaid");
+        ArrayList<String> alldates = yearToDate(year + "-12");
+        SQLFactory sqlFactory = new SQLFactory(this, "依人员统计订单");
+        if (type == 1) {
+            sqlFactory = new SQLFactory(this, "依人员统计订单");
+        }
+        if (type == 2) {
+            sqlFactory = new SQLFactory(this, "依医院统计订单");
+        }
+        if (type == 3) {
+            sqlFactory = new SQLFactory(this, "依经销商统计订单");
+        }
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        sqlFactory.addParameter("befyear", befyear);
+        Rows rows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap salesRowsMap = rows.toRowsMap("sa_saleareaid");
+
+        sqlFactory = new SQLFactory(this, "依人员统计目标");
+        if (type == 1) {
+            sqlFactory = new SQLFactory(this, "依人员统计目标");
+        }
+        if (type == 2) {
+            sqlFactory = new SQLFactory(this, "依医院统计目标");
+        }
+        if (type == 3) {
+            sqlFactory = new SQLFactory(this, "依经销商统计目标");
+        }
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        Rows targetrows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap targetRowsMap = targetrows.toRowsMap("sa_saleareaid");
+
+        Rows datas = new Rows();
+        for (String sa_saleareaid : saleareaids) {
+            Rows salesRows = salesRowsMap.getOrDefault(sa_saleareaid, new Rows());
+            RowsMap dateDateRow = salesRows.toRowsMap("ym");
+            Rows targetRows = targetRowsMap.getOrDefault(sa_saleareaid, new Rows());
+            for (String date : alldates) {
+                Rows dateDate = dateDateRow.getOrDefault(date, new Rows());
+                Row row = new Row();
+                row.put("sa_saleareaid", sa_saleareaid);
+                row.put("ym", date);
+                row.put("amount", dateDate.isNotEmpty() ? dateDate.get(0).getBigDecimal("amount") : 0);
+                //根据日期中的月份(如 "11")从 targetRows 中动态取出对应的 m{月}amount 字段值
+                String monthPart = date.split("-")[1];
+                String fieldName = "m" + Integer.parseInt(monthPart) + "amount";
+                BigDecimal target = BigDecimal.ZERO;
+                if (!targetRows.isEmpty()) {
+                    Object val = targetRows.get(0).get(fieldName);
+                    if (val instanceof BigDecimal) {
+                        target = (BigDecimal) val;
+                    } else if (val != null) {
+                        target = new BigDecimal(val.toString());
+                    }
+                }
+                row.put("target", target);
+                datas.add(row);
+            }
+        }
+
+        RowsMap dataRowsMap = datas.toRowsMap("sa_saleareaid");
+
+        for (Row arearow : arearows) {
+            Rows dataRows = dataRowsMap.getOrDefault(arearow.getString("sa_saleareaid"), new Rows());
+            //计算当前月份
+            ArrayList<String> dates = new ArrayList<>();
+            dates.add(currentMonth);
+            calculate("m", arearow, dataRows, dates);
+            //计算季度
+            calculate("s", arearow, dataRows, quarterToDate(currentMonth));
+            //计算年度
+            calculate("y", arearow, dataRows, yearToDate(currentMonth));
+        }
+
+
+        return getSucReturnObject().setData(arearows).toString();
+    }
+
+    @API(title = "人员目标", apiversion = R.ID2025122611132802.v1.class)
+    public String peopleTarget() throws YosException {
+        int year = content.getIntValue("year");
+        int befyear = year - 1;
+        Long sa_saleareaid = content.getLongValue("sa_saleareaid");
+
+        Rows arearows = dbConnect.runSqlQuery(" SELECT t1.*,t3.`name`,t3.userid FROM view_areas t1 " +
+                " INNER JOIN sa_salearea_hr t2 ON t2.sa_saleareaid=t1.sa_saleareaid " +
+                " INNER JOIN sys_hr t3 ON t3.hrid=t2.hrid " +
+                " WHERE t1.siteid='" + siteid + "' AND t1.parentid=" + sa_saleareaid +
+                " ORDER BY t1.parentid,t1.sa_saleareaid");
+
+
+        SQLFactory sqlFactory = new SQLFactory(this, "按人员分组统计订单");
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        sqlFactory.addParameter("befyear", befyear);
+        Rows rows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap salesRowsMap = rows.toRowsMap("userid");
+
+        sqlFactory = new SQLFactory(this, "按人员分组统计目标");
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        Rows targetrows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap targetRowsMap = targetrows.toRowsMap("userid");
+
+        ArrayList<String> userids = arearows.toArrayList("userid");
+        ArrayList<String> alldates = yearToDate(year + "-12");
+        Rows datas = new Rows();
+        for (String userid : userids) {
+            Rows salesRows = salesRowsMap.getOrDefault(userid, new Rows());
+            RowsMap dateDateRow = salesRows.toRowsMap("ym");
+            Rows targetRows = targetRowsMap.getOrDefault(userid, new Rows());
+            for (String date : alldates) {
+                Rows dateDate = dateDateRow.getOrDefault(date, new Rows());
+                Row row = new Row();
+                row.put("userid", userid);
+                row.put("ym", date);
+                row.put("amount", dateDate.isNotEmpty() ? dateDate.get(0).getBigDecimal("amount") : 0);
+                //根据日期中的月份(如 "11")从 targetRows 中动态取出对应的 m{月}amount 字段值
+                String monthPart = date.split("-")[1];
+                String fieldName = "m" + Integer.parseInt(monthPart) + "amount";
+                BigDecimal target = BigDecimal.ZERO;
+                if (!targetRows.isEmpty()) {
+                    Object val = targetRows.get(0).get(fieldName);
+                    if (val instanceof BigDecimal) {
+                        target = (BigDecimal) val;
+                    } else if (val != null) {
+                        target = new BigDecimal(val.toString());
+                    }
+                }
+                row.put("target", target);
+                datas.add(row);
+            }
+        }
+
+        RowsMap dataRowsMap = datas.toRowsMap("userid");
+
+        for (Row arearow : arearows) {
+            Rows dataRows = dataRowsMap.getOrDefault(arearow.getString("userid"), new Rows());
+            //计算月份
+            for (String date : alldates) {
+                String monthPart = date.split("-")[1];
+                String fieldName = "m" + Integer.parseInt(monthPart);
+                calculate(fieldName, arearow, dataRows, date);
+            }
+        }
+
+        return getSucReturnObject().setData(arearows).toString();
+    }
+
+    @API(title = "医院目标", apiversion = R.ID2025122611135102.v1.class)
+    public String hospitalTarget() throws YosException {
+        int year = content.getIntValue("year");
+        int befyear = year - 1;
+        Long sa_saleareaid = content.getLongValue("sa_saleareaid");
+
+        Rows arearows = dbConnect.runSqlQuery("SELECT t1.*,t3.`enterprisename` hospitalname,t2.sa_customersid FROM view_areas t1 " +
+                " INNER JOIN sa_customers t2 ON t2.sa_saleareaid=t1.sa_saleareaid " +
+                " INNER JOIN sys_enterprise t3 ON t3.sys_enterpriseid=t2.sys_enterpriseid " +
+                " WHERE t1.siteid='" + siteid + "' AND t1.parentid= " + sa_saleareaid + " " +
+                " ORDER BY t1.parentid,t1.sa_saleareaid ");
+
+
+        SQLFactory sqlFactory = new SQLFactory(this, "按医院分组统计订单");
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        sqlFactory.addParameter("befyear", befyear);
+        Rows rows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap salesRowsMap = rows.toRowsMap("sa_customersid");
+
+        sqlFactory = new SQLFactory(this, "按医院分组统计目标");
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        Rows targetrows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap targetRowsMap = targetrows.toRowsMap("sa_customersid");
+
+        ArrayList<String> sa_customersids = arearows.toArrayList("sa_customersid");
+        ArrayList<String> alldates = yearToDate(year + "-12");
+        Rows datas = new Rows();
+        for (String sa_customersid : sa_customersids) {
+            Rows salesRows = salesRowsMap.getOrDefault(sa_customersid, new Rows());
+            RowsMap dateDateRow = salesRows.toRowsMap("ym");
+            Rows targetRows = targetRowsMap.getOrDefault(sa_customersid, new Rows());
+            for (String date : alldates) {
+                Rows dateDate = dateDateRow.getOrDefault(date, new Rows());
+                Row row = new Row();
+                row.put("sa_customersid", sa_customersid);
+                row.put("ym", date);
+                row.put("amount", dateDate.isNotEmpty() ? dateDate.get(0).getBigDecimal("amount") : 0);
+                //根据日期中的月份(如 "11")从 targetRows 中动态取出对应的 m{月}amount 字段值
+                String monthPart = date.split("-")[1];
+                String fieldName = "m" + Integer.parseInt(monthPart) + "amount";
+                BigDecimal target = BigDecimal.ZERO;
+                if (!targetRows.isEmpty()) {
+                    Object val = targetRows.get(0).get(fieldName);
+                    if (val instanceof BigDecimal) {
+                        target = (BigDecimal) val;
+                    } else if (val != null) {
+                        target = new BigDecimal(val.toString());
+                    }
+                }
+                row.put("target", target);
+                datas.add(row);
+            }
+        }
+
+        RowsMap dataRowsMap = datas.toRowsMap("sa_customersid");
+
+        for (Row arearow : arearows) {
+            Rows dataRows = dataRowsMap.getOrDefault(arearow.getString("sa_customersid"), new Rows());
+            //计算月份
+            for (String date : alldates) {
+                String monthPart = date.split("-")[1];
+                String fieldName = "m" + Integer.parseInt(monthPart);
+                calculate(fieldName, arearow, dataRows, date);
+            }
+        }
+
+        return getSucReturnObject().setData(arearows).toString();
+    }
+
+    @API(title = "经销商目标", apiversion = R.ID2025122714510802.v1.class)
+    public String agentTarget() throws YosException {
+        int year = content.getIntValue("year");
+        int befyear = year - 1;
+        Long sa_saleareaid = content.getLongValue("sa_saleareaid");
+
+        Rows arearows = dbConnect.runSqlQuery("SELECT t1.*,t3.enterprisename,t2.sa_agentsid FROM view_areas t1 " +
+                " INNER JOIN sys_enterprise_tradefield t2 ON t2.sa_saleareaid=t1.sa_saleareaid " +
+                " INNER JOIN sys_enterprise t3 ON t3.sys_enterpriseid=t2.sys_enterpriseid " +
+                " WHERE t1.siteid='" + siteid + "' AND t1.parentid= " + sa_saleareaid + " " +
+                " ORDER BY t1.parentid,t1.sa_saleareaid ");
+
+
+        SQLFactory sqlFactory = new SQLFactory(this, "按经销商分组统计订单");
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        sqlFactory.addParameter("befyear", befyear);
+        Rows rows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap salesRowsMap = rows.toRowsMap("sa_agentsid");
+
+        sqlFactory = new SQLFactory(this, "按经销商分组统计目标");
+        sqlFactory.addParameter("siteid", siteid);
+        sqlFactory.addParameter("year", year);
+        Rows targetrows = dbConnect.runSqlQuery(sqlFactory);
+        RowsMap targetRowsMap = targetrows.toRowsMap("sa_agentsid");
+
+        ArrayList<String> sa_agentsids = arearows.toArrayList("sa_agentsid");
+        ArrayList<String> alldates = yearToDate(year + "-12");
+        Rows datas = new Rows();
+        for (String sa_agentsid : sa_agentsids) {
+            Rows salesRows = salesRowsMap.getOrDefault(sa_agentsid, new Rows());
+            RowsMap dateDateRow = salesRows.toRowsMap("ym");
+            Rows targetRows = targetRowsMap.getOrDefault(sa_agentsid, new Rows());
+            for (String date : alldates) {
+                Rows dateDate = dateDateRow.getOrDefault(date, new Rows());
+                Row row = new Row();
+                row.put("sa_agentsid", sa_agentsid);
+                row.put("ym", date);
+                row.put("amount", dateDate.isNotEmpty() ? dateDate.get(0).getBigDecimal("amount") : 0);
+                //根据日期中的月份(如 "11")从 targetRows 中动态取出对应的 m{月}amount 字段值
+                String monthPart = date.split("-")[1];
+                String fieldName = "m" + Integer.parseInt(monthPart) + "amount";
+                BigDecimal target = BigDecimal.ZERO;
+                if (!targetRows.isEmpty()) {
+                    Object val = targetRows.get(0).get(fieldName);
+                    if (val instanceof BigDecimal) {
+                        target = (BigDecimal) val;
+                    } else if (val != null) {
+                        target = new BigDecimal(val.toString());
+                    }
+                }
+                row.put("target", target);
+                datas.add(row);
+            }
+        }
+
+        RowsMap dataRowsMap = datas.toRowsMap("sa_agentsid");
+
+        for (Row arearow : arearows) {
+            Rows dataRows = dataRowsMap.getOrDefault(arearow.getString("sa_agentsid"), new Rows());
+            //计算月份
+            for (String date : alldates) {
+                String monthPart = date.split("-")[1];
+                String fieldName = "m" + Integer.parseInt(monthPart);
+                calculate(fieldName, arearow, dataRows, date);
+            }
+        }
+
+        return getSucReturnObject().setData(arearows).toString();
+    }
+
+
+    public void calculate(String key, Row arearow, Rows dataRows, ArrayList<String> dates) {
+        BigDecimal saleamount = BigDecimal.ZERO;
+        BigDecimal saleamount_mom = BigDecimal.ZERO;
+        BigDecimal saleamount_yoy = BigDecimal.ZERO;
+        BigDecimal targetmount = BigDecimal.ZERO;
+        for (String month : dates) {
+            for (Row dataRow : dataRows) {
+                String ym = dataRow.getString("ym");
+                String momMonth = getMomMonth(month);
+                String yoyMonth = getYoyMonth(month);
+                BigDecimal amount = dataRow.getBigDecimal("amount");
+                BigDecimal target = dataRow.getBigDecimal("target");
+                if (ym.equals(month)) {
+                    saleamount = saleamount.add(amount);
+                    targetmount = targetmount.add(target);
+                }
+                if (ym.equals(momMonth)) {
+                    saleamount_mom = saleamount_mom.add(amount);
+                }
+                if (ym.equals(yoyMonth)) {
+                    saleamount_yoy = saleamount_yoy.add(amount);
+                }
+            }
+        }
+        arearow.putIfAbsent(key + "_saleamount", saleamount);
+        arearow.putIfAbsent(key + "_saleamount_mom", saleamount_mom);
+        arearow.putIfAbsent(key + "_saleamount_yoy", saleamount_yoy);
+        arearow.putIfAbsent(key + "_targetamount", targetmount);
+        //计算达成率
+        if (targetmount.compareTo(BigDecimal.ZERO) == 0) {
+            arearow.put(key + "_rate_achieve", "-");
+        } else {
+            arearow.put(key + "_rate_achieve", (saleamount.divide(targetmount, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP) + "%");
+        }
+        //计算环比
+        if (saleamount_mom.compareTo(BigDecimal.ZERO) == 0) {
+            arearow.put(key + "_rate_mom", "-");
+        } else {
+            arearow.put(key + "_rate_mom", ((saleamount.subtract(saleamount_mom)).divide(saleamount_mom, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP) + "%");
+        }
+        //计算同比
+        if (saleamount_yoy.compareTo(BigDecimal.ZERO) == 0) {
+            arearow.put(key + "_rate_yoy", "-");
+        } else {
+            arearow.put(key + "_rate_yoy", ((saleamount.subtract(saleamount_yoy)).divide(saleamount_yoy, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP) + "%");
+        }
+    }
+
+    public void calculate(String key, Row arearow, Rows dataRows, String month) {
+        BigDecimal saleamount = BigDecimal.ZERO;
+        BigDecimal saleamount_mom = BigDecimal.ZERO;
+        BigDecimal saleamount_yoy = BigDecimal.ZERO;
+        BigDecimal targetmount = BigDecimal.ZERO;
+
+        for (Row dataRow : dataRows) {
+            String ym = dataRow.getString("ym");
+            String momMonth = getMomMonth(month);
+            String yoyMonth = getYoyMonth(month);
+            BigDecimal amount = dataRow.getBigDecimal("amount");
+            BigDecimal target = dataRow.getBigDecimal("target");
+            if (ym.equals(month)) {
+                saleamount = saleamount.add(amount);
+                targetmount = targetmount.add(target);
+            }
+            if (ym.equals(momMonth)) {
+                saleamount_mom = saleamount_mom.add(amount);
+            }
+            if (ym.equals(yoyMonth)) {
+                saleamount_yoy = saleamount_yoy.add(amount);
+            }
+        }
+
+        arearow.putIfAbsent(key + "_saleamount", saleamount);
+        arearow.putIfAbsent(key + "_saleamount_mom", saleamount_mom);
+        arearow.putIfAbsent(key + "_saleamount_yoy", saleamount_yoy);
+        arearow.putIfAbsent(key + "_targetamount", targetmount);
+        //计算达成率
+        if (targetmount.compareTo(BigDecimal.ZERO) == 0) {
+            arearow.put(key + "_rate_achieve", "-");
+        } else {
+            arearow.put(key + "_rate_achieve", (saleamount.divide(targetmount, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP) + "%");
+        }
+        //计算环比
+        if (saleamount_mom.compareTo(BigDecimal.ZERO) == 0) {
+            arearow.put(key + "_rate_mom", "-");
+        } else {
+            arearow.put(key + "_rate_mom", ((saleamount.subtract(saleamount_mom)).divide(saleamount_mom, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP) + "%");
+        }
+        //计算同比
+        if (saleamount_yoy.compareTo(BigDecimal.ZERO) == 0) {
+            arearow.put(key + "_rate_yoy", "-");
+        } else {
+            arearow.put(key + "_rate_yoy", ((saleamount.subtract(saleamount_yoy)).divide(saleamount_yoy, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP) + "%");
+        }
+        arearow.put("month", month);
+    }
+
+    //当年1月 到 指定月份
+    public static ArrayList<String> yearToDate(String yearMonthStr) {
+        YearMonth target = YearMonth.parse(yearMonthStr);
+
+        ArrayList<String> yearToDate = new ArrayList<>();
+        YearMonth startOfYear = YearMonth.of(target.getYear(), 1);
+        for (YearMonth ym = startOfYear; !ym.isAfter(target); ym = ym.plusMonths(1)) {
+            yearToDate.add(ym.toString());
+        }
+        return yearToDate;
+    }
+
+    //  季度起始月 到 指定月份
+    public static ArrayList<String> quarterToDate(String yearMonthStr) {
+        YearMonth target = YearMonth.parse(yearMonthStr);
+        int quarter = target.get(IsoFields.QUARTER_OF_YEAR); // 1~4
+        int startMonthOfQuarter = (quarter - 1) * 3 + 1;   // Q1=1, Q2=4, Q3=7, Q4=10
+        YearMonth startOfQuarter = YearMonth.of(target.getYear(), startMonthOfQuarter);
+
+        ArrayList<String> quarterToDate = new ArrayList<>();
+        for (YearMonth ym = startOfQuarter; !ym.isAfter(target); ym = ym.plusMonths(1)) {
+            quarterToDate.add(ym.toString());
+        }
+        return quarterToDate;
+    }
+
+    //环比日期
+    public static String getMomMonth(String yyyyMM) {
+        YearMonth ym = YearMonth.parse(yyyyMM);
+        return ym.minusMonths(1).format(DateTimeFormatter.ofPattern("yyyy-MM"));
+    }
+
+    //同比日期
+    public static String getYoyMonth(String yyyyMM) {
+        YearMonth ym = YearMonth.parse(yyyyMM);
+        return ym.minusYears(1).format(DateTimeFormatter.ofPattern("yyyy-MM"));
+    }
+}