Jelajahi Sumber

1、修复软床报价部分部件选配清单没有带出问题
2、修复软床报价重复材料报错问题
3、软床报价,新增其他tab页,记录不属于床架床头床头柜范畴的材料
4、迁移CommonDynamicSelect到CommonHelper
5、新增批量insert方法

MY 2 minggu lalu
induk
melakukan
6010c69d7d

+ 1 - 0
JLHHJSvr/Com/GetChangeSoftBedMxList.cs

@@ -21,6 +21,7 @@ namespace JLHHJSvr.Com
         /// 单据id
         /// </summary>
         public int billid { get; set; }
+        public List<u_softbed_mx> mxList { get; set; }
         /// <summary>
         /// 配置项值
         /// </summary>

+ 1 - 0
JLHHJSvr/Com/Model/u_configure_codemxbom.cs

@@ -33,6 +33,7 @@ namespace JLHHJSvr.Com.Model
         public decimal default_width { get; set; }
         public decimal default_qty { get; set; }
         #region 辅助
+        public string pzname { get; set; }
         public string mtrlname { get; set; }
         public string mtrlcode { get; set; }
         public string mtrlmode { get; set; }

+ 1 - 0
JLHHJSvr/Com/Model/u_softbed.cs

@@ -50,6 +50,7 @@ namespace JLHHJSvr.Com.Model
         public decimal total_hr_cost { get; set; }
         public decimal total_cost { get; set; }
         public int version { get; set; }
+        public int copy_id { get; set; }
 
         public List<u_softbed_mx> mxList { get; set; }
         /// <summary>

+ 2 - 2
JLHHJSvr/Com/Model/u_softbed_mx.cs

@@ -34,9 +34,9 @@ namespace JLHHJSvr.Com.Model
         public string price_formula_str { get; set; }
         public decimal cost_price { get; set; }
         public decimal cost_amt { get; set; }
-
-        #region 辅助
         public string pzname { get; set; }
+        public string parts_type { get; set; }
+        #region 辅助
         public string formulaname { get; set; }
         #endregion
     }

+ 4 - 0
JLHHJSvr/Com/SaveSoftBedQuote.cs

@@ -14,6 +14,10 @@ namespace JLHHJSvr.Com
         /// 软床信息:主表
         /// </summary>
         public u_softbed softbed { get; set; }
+        /// <summary>
+        /// 保存类型
+        /// </summary>
+        public string type { get; set; }
     }
 
     public sealed class SaveSoftBedQuoteResponse : LJResponse

+ 70 - 1
JLHHJSvr/DBA/DAL_SQLite/DbSqlHelper.cs

@@ -646,8 +646,77 @@ namespace LJLib.DAL.SQL
         public static int Insert<TCommand, T>(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand
         {
             return Insert(cmd, null, null, modle, fields);
-;        }
+        }
+
+        /// <summary>
+        /// 批量插入数据到数据库
+        /// </summary>
+        /// <typeparam name="TCommand">数据库命令类型</typeparam>
+        /// <typeparam name="T">数据模型类型</typeparam>
+        /// <param name="cmd">数据库命令对象</param>
+        /// <param name="models">要插入的数据列表</param>
+        /// <param name="targetTable">目标表名</param>
+        /// <param name="maps">字段映射字典,key为数据库字段名,value为模型属性名</param>
+        /// <param name="fields">要插入的字段,默认为"*"</param>
+        /// <returns>成功插入的记录数</returns>
+        public static int BulkInsert<TCommand, T>(TCommand cmd, IList<T> models, string targetTable, Dictionary<string, string> maps = null, string fields = "*") where TCommand : DbCommand
+        {
+            if (models == null || models.Count == 0)
+            {
+                return 0;
+            }
+
+            var targetfields = GetTargetMaps<T>(maps, fields);
+            if (targetfields.Count == 0)
+            {
+                throw new Exception("没有一个有效插入字段");
+            }
+
+            // 构建多值INSERT SQL语句
+            string fieldList = string.Join(", ", targetfields.Keys);
+            var valueClauses = new List<string>();
+            var parameters = new Dictionary<string, object>();
+
+            // 为每条数据创建VALUES子句
+            for (int i = 0; i < models.Count; i++)
+            {
+                var model = models[i];
+                var paramNames = new List<string>();
+
+                foreach (var field in targetfields)
+                {
+                    string paramName = $"@p{i}_{field.Key}";
+                    var propertyValue = field.Value.GetGetMethod().Invoke(model, null);
+                    parameters[paramName] = propertyValue ?? DBNull.Value;
+                    paramNames.Add(paramName);
+                }
 
+                valueClauses.Add($"({string.Join(", ", paramNames)})");
+            }
+
+            // 构建完整的INSERT语句
+            cmd.CommandText = $"INSERT INTO {targetTable}({fieldList}) VALUES {string.Join(", ", valueClauses)}";
+            cmd.CommandType = CommandType.Text;
+            cmd.Parameters.Clear();
+
+            // 添加所有参数
+            foreach (var param in parameters)
+            {
+                AddWithValue(cmd, param.Key, param.Value);
+            }
+
+            try
+            {
+                return cmd.ExecuteNonQuery();
+            }
+            catch (Exception ex)
+            {
+                Trace.Write($"BulkInsert Error: {ex.Message}");
+                Trace.Write($"SQL: {cmd.CommandText}");
+                Trace.Write($"Models Count: {models.Count}");
+                throw;
+            }
+        }
         private static Dictionary<string, PropertyInfo> GetTargetMaps<T>(IDictionary<string, string> maps, string fields)
         {
             var newmaps = new Dictionary<string, string>();

+ 19 - 0
JLHHJSvr/DataStore/_Mapper_softbed_accessory.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<data>
+	<json>
+		[
+			{
+				"label": "外套",
+				"value": 1
+			},
+			{
+				"label": "五金配件",
+				"value": 1
+			},
+			{
+				"label": "包装配件",
+				"value": 1
+			}
+		]
+	</json>
+</data>

+ 4 - 0
JLHHJSvr/DataStore/web_configure_codemxbomlist.xml

@@ -27,6 +27,7 @@ SELECT u_configure_codemxbom.pzid
 	,u_mtrldef.usermtrlmode
 FROM u_configure_codemxbom
 INNER JOIN u_mtrldef ON u_configure_codemxbom.mtrlid = u_mtrldef.mtrlid
+INNER JOIN u_configure_code ON u_configure_codemxbom.pzid = u_configure_code.pzid
   </selectstr>
   <where>
 	<when notnull="@pzid">
@@ -35,6 +36,9 @@ INNER JOIN u_mtrldef ON u_configure_codemxbom.mtrlid = u_mtrldef.mtrlid
 	<when notnull="@printid">
 		u_configure_codemxbom.printid = @printid
 	</when>
+	<when notnull="@typeid">
+		u_configure_code.typeid = @typeid 
+	</when>
   </where>
   <orderstr>pid</orderstr>
   <displayfields>

+ 1 - 1
JLHHJSvr/Excutor/GetChangeSoftBedMxListExcutor.cs

@@ -36,7 +36,7 @@ namespace JLHHJSvr.Excutor
                 con.Open();
 
                 var softbedHelpr = HelperBase.GetHelper<SoftBedHelper>(cmd, new HelperBase.Context() { tokendata = tokendata });
-                rslt.mxList = softbedHelpr.GetChangeSoftBedMxList(request.billid,request.codeList);
+                rslt.mxList = softbedHelpr.GetChangeSoftBedMxList(request.billid,request.mxList,request.codeList);
             }
         }
     }

+ 19 - 8
JLHHJSvr/Excutor/SaveSoftBedQuoteExcutor.cs

@@ -24,15 +24,26 @@ namespace JLHHJSvr.Excutor
                 {
                     try
                     {
-                        softBedHelper.SaveSoftBed(request.softbed);
-
-                        rslt.softbed = new u_softbed()
+                        if(!string.IsNullOrWhiteSpace(request.type) && request.type == "copy")
                         {
-                            softbed_id = request.softbed.softbed_id,
-                            softbed_code = request.softbed.softbed_code,
-                            softbed_name = request.softbed.softbed_name,
-                            softbed_relcode = request.softbed.softbed_relcode
-                        };
+                            var result = softBedHelper.CopySoftBed(request.softbed);
+                            rslt.softbed = new u_softbed()
+                            {
+                                softbed_id = result.softbed_id,
+                                softbed_code = result.softbed_code,
+                                softbed_name = result.softbed_name,
+                                softbed_relcode = result.softbed_relcode
+                            };
+                        } else { 
+                            softBedHelper.SaveSoftBed(request.softbed);
+                            rslt.softbed = new u_softbed()
+                            {
+                                softbed_id = request.softbed.softbed_id,
+                                softbed_code = request.softbed.softbed_code,
+                                softbed_name = request.softbed.softbed_name,
+                                softbed_relcode = request.softbed.softbed_relcode
+                            };
+                        }
 
                         cmd.Transaction.Commit();
                     }

+ 87 - 0
JLHHJSvr/Helper/BasicInfoHelper.cs

@@ -4,9 +4,11 @@ using JLHHJSvr.Com.Model;
 using JLHHJSvr.LJException;
 using JLHHJSvr.Tools;
 using LJLib.DAL.SQL;
+using NPOI.SS.Formula.Functions;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
 using static JLHHJSvr.Helper.CacheHelper;
 
 namespace JLHHJSvr.Helper
@@ -37,6 +39,26 @@ namespace JLHHJSvr.Helper
             }
         }
         /// <summary>
+        /// 核价选配项-保存
+        /// </summary>
+        /// <param name="configure"></param>
+        public void SaveConfigureCode(u_configure_code configure)
+        {
+            if (configure.pzid <= 0)
+            {
+                // 新增
+                configure.pzid = BllHelper.GetID(cmd, "u_configure_code"); 
+                var fields = @"typeid,pzid,pzcode,inputtype,name,configtype,ifcross,ifcheck,ifuse,rulestr,ifnum,decnum,maxnum,minnum,pricestr,priceratestr,ifpack,zj_special";
+                DbSqlHelper.Insert(cmd, "u_configure_code", null, configure, fields);
+            }
+            else
+            {
+                //修改
+                var fields = @"pzcode,inputtype,name,configtype,ifcross,ifcheck,ifuse,rulestr,ifnum,decnum,maxnum,minnum,pricestr,priceratestr,ifpack,zj_special";
+                DbSqlHelper.Update(cmd, "u_configure_code", null, configure, "typeid,pzid", fields);
+            }
+        }
+        /// <summary>
         /// 核价选配项值-保存
         /// </summary>
         /// <param name="configure"></param>
@@ -67,6 +89,71 @@ namespace JLHHJSvr.Helper
                 DbSqlHelper.Update(cmd, "u_configure_codemx", null, codeMx, "pzid,printid", fields);
             }
         }
+        /// <summary>
+        /// 核价选配项值物料清单-保存
+        /// </summary>
+        /// <param name="configure"></param>
+        public void SaveConfigureCodeMxBomList(List<u_configure_codemxbom> bomList)
+        {
+            var sb = new StringBuilder();
+            var saveList = new List<u_configure_codemxbom>();
+            foreach (var bom in bomList)
+            {
+                AutoInit.AutoInitS(cmd, bom);
+
+                if (bom.pzid <= 0)
+                {
+                    sb.AppendLine($"物料:{bom.mtrlname}配置项ID错误!\r\n");
+                }
+
+                if (bom.printid <= 0)
+                {
+                    sb.AppendLine($"物料:{bom.mtrlname}配置值ID错误!\r\n");
+                }
+
+                if (sb.Length > 0)
+                {
+                    continue;
+                }
+                saveList.Add(bom);
+            }
+
+            if (sb.Length > 0) throw new LJCommonException(sb.ToString());
+
+            var fields = @"mtrlid,sonscale,sonscale_formula,mng_cost_rate,profit_rate,realqty,sonloss,sonloss_formula,sondecloss,sondecloss_formula,default_length,default_width,default_qty";
+            foreach (var item in saveList)
+            {
+                if (item.pid <= 0)
+                {
+                    // 新增
+                    fields += ",pzid,printid,pid";
+                    int _pid = 0;
+                    cmd.CommandText = @"SELECT ISNULL(MAX(pid),0) AS pid FROM u_configure_codemxbom WHERE pzid = @pzid AND printid = @printid";
+                    cmd.Parameters.Clear();
+                    cmd.Parameters.AddWithValue("@pzid", item.pzid);
+                    cmd.Parameters.AddWithValue("@printid", item.printid);
+                    using (var reader = cmd.ExecuteReader())
+                    {
+                        if (reader.Read())
+                        {
+                            _pid = Convert.ToInt32(reader["pid"]);
+                        }
+                    }
+                    item.pid = _pid + 1;
+                    DbSqlHelper.Insert(cmd, "u_configure_codemxbom", null, item, fields);
+                }
+                else
+                {
+                    // 修改
+                    DbSqlHelper.Update(cmd, "u_configure_codemxbom", null, item, "pzid,printid,pid", fields);
+                }
+            }
+        }
+        /// <summary>
+        /// 核价软工公式定义-删除
+        /// </summary>
+        /// <param name="formula"></param>
+        /// <exception cref="LJCommonException"></exception>
         public void DeleteSoftBedFormula(u_softbed_formula formula)
         {
             if (formula == null || formula.formulaid <= 0)

File diff ditekan karena terlalu besar
+ 1108 - 0
JLHHJSvr/Helper/CommonHelper.cs


+ 241 - 116
JLHHJSvr/Helper/SoftBedHelper.cs

@@ -5,16 +5,20 @@ using JLHHJSvr.Excutor;
 using JLHHJSvr.LJException;
 using JLHHJSvr.Tools;
 using LJLib.DAL.SQL;
+using NPOI.HSSF.Record;
 using NPOI.SS.Formula.Functions;
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Data;
 using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using System.Web;
+using System.Web.Configuration;
 using static JLHHJSvr.Helper.CacheHelper;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement.Tab;
 
 namespace JLHHJSvr.Helper
 {
@@ -45,7 +49,7 @@ namespace JLHHJSvr.Helper
         public List<u_softbed_mx> GetSoftBedMxList(int billid,string fields = null)
         {
             fields = fields ?? @"softbed_id,printid,formulaid,pzid,mtrlid,mtrlname,mtrlcode,mtrlmode,unit,has_type,allow_edit,cutting_length,cutting_width,cutting_qty,
-                                useqty,use_formula,use_formula_str,actual_useqty,loss_rate,price,price_formula,price_formula_str,cost_price,cost_amt,pzname,formulaname";
+                                useqty,use_formula,use_formula_str,actual_useqty,loss_rate,price,price_formula,price_formula_str,cost_price,cost_amt,pzname,formulaname,parts_type";
             var mxlist = new List<u_softbed_mx>();
 
             var selectStr = @"SELECT u_softbed_mx.softbed_id
@@ -72,7 +76,8 @@ namespace JLHHJSvr.Helper
 									,u_softbed_mx.price_formula_str
 									,u_softbed_mx.cost_price
 									,u_softbed_mx.cost_amt
-									,ISNULL(u_configure_code.name,'') AS pzname
+									,ISNULL(u_configure_code.name,u_softbed_mx.pzname) AS pzname
+									,u_softbed_mx.parts_type
 									,ISNULL(u_softbed_formula.formulaname,'') AS formulaname
 								FROM u_softbed_mx
 								LEFT JOIN u_configure_code ON u_softbed_mx.pzid = u_configure_code.pzid
@@ -83,109 +88,112 @@ namespace JLHHJSvr.Helper
 
 			return mxlist;
         }
-		public List<u_softbed_mx> GetChangeSoftBedMxList(int billid,List<u_configure_codemx> codeMxList)
+		public List<u_softbed_mx> GetChangeSoftBedMxList(int billid,List<u_softbed_mx> mxList,List<u_configure_codemx> codeMxList)
 		{
 			var newList = new List<u_softbed_mx>();
-
-			var softbed = GetSoftBed(billid, "billid,softbed_code,has_headboard,has_nightstand,has_bedframe");
+			var pzid0List = new List<u_softbed_mx>();
+			var softbed = GetSoftBed(billid, "billid,softbed_code,has_headboard,has_nightstand,has_bedframe,is_template,template_id");
 			if (softbed == null) return newList;
-
-			// 物料清单
-			var mxList = GetSoftBedMxList(billid);
-			// 换料清单
-			var bomList = GetSoftBedMxBomList(codeMxList);
-            // 排除不存在配置的物料
-            //var skipList = new List<int>();
-            //var mxMtrlIds = mxList.Select(t => t.mtrlid).ToList();
-            //if (mxMtrlIds.Count > 0)
+            // 换料清单
+            var bomList = GetSoftBedMxBomList(codeMxList);
+            //         var typeDict = new Dictionary<string, List<u_softbed_mx>>();
+            //foreach(var mx in mxList)
             //{
-            //    cmd.CommandText = $@"SELECT mtrlid FROM u_configure_codemxbom WHERE mtrlid NOT IN {ListEx.getString(mxMtrlIds)}";
-            //    cmd.Parameters.Clear();
-            //    using (var reader = cmd.ExecuteReader())
-            //    {
-            //        while (reader.Read())
-            //        {
-            //            skipList.Add(Convert.ToInt32(reader["mtrlid"]));
-            //        }
-            //    }
-            //}
-
-			foreach (var mx in mxList)
-			{
-				if (mx.pzid > 0)
-				{
-					// 部件
-					var tmp_bomList = bomList.FindAll(t => t.has_type == mx.has_type && t.pzid == mx.pzid);
-					if (tmp_bomList.Count > 0)
-					{
-						// add
-						foreach (var temp in tmp_bomList)
-						{
-							if (temp.mtrlid == mx.mtrlid)
-							{
-								mx.printid = newList.Count + 1;
-								newList.Add(mx);
-							}
-							else
-							{
-								temp.printid = newList.Count + 1;
-								newList.Add(temp);
-							}
-						}
-					}
-				}
-				else
-				{
-                    // 非部件
-                    string contfigtypename = string.Empty;
-                    string prefix = $"{softbed.softbed_code}|";
-                    if (mx.has_type == 1) contfigtypename = $"{prefix}床头";
-                    else if (mx.has_type == 2) contfigtypename = $"{prefix}床头柜";
-                    else contfigtypename = $"{prefix}床架";
+            //	var key = $"{mx.has_type}|{mx.pzid}";
+            //	if(!typeDict.ContainsKey(key))
+            //	{
+            //		typeDict.Add(key, new List<u_softbed_mx>());
+            //	}
 
-                    cmd.CommandText = @"SELECT u_configure_code.pzid
-										FROM u_configure_codemxbom
-										INNER JOIN u_configure_codemx ON u_configure_codemxbom.pzid = u_configure_codemx.pzid
-											AND u_configure_codemxbom.printid = u_configure_codemx.printid
-										INNER JOIN u_configure_code ON u_configure_codemx.pzid = u_configure_code.pzid
-										INNER JOIN u_configure_type ON u_configure_code.typeid = u_configure_type.contfigtypeid
-										WHERE u_configure_codemxbom.mtrlid = @mtrlid AND LTRIM(RTRIM(u_configure_type.contfigtypename)) = @contfigtypename";
-					cmd.Parameters.Clear();
-					cmd.Parameters.AddWithValue("@mtrlid",mx.mtrlid);
-                    cmd.Parameters.AddWithValue("@contfigtypename", contfigtypename);
-					int pzid = 0, cnt = 0; 
-					using(var reader = cmd.ExecuteReader())
-					{
-						while(reader.Read())
-						{
-							pzid = Convert.ToInt32(reader["pzid"]);
-							cnt++;
-						}
-					}
+            //	typeDict[key].Add(mx);
+
+            //	if (mx.pzid == 0) pzid0List.Add(mx);
+            //         }
 
-					if (cnt > 1) throw new LJCommonException($"换料失败,原因:{contfigtypename}的{mx.mtrlname}存在多个清单,但没有部件!");
+            // 原Dictionary替换为List<KeyValuePair>,维护键值对的插入顺序
+            var typeList = new List<KeyValuePair<string, List<u_softbed_mx>>>();
+            foreach (var mx in mxList)
+            {
+                var key = $"{mx.has_type}|{mx.pzid}";
+                var existingItem = typeList.FirstOrDefault(kvp => kvp.Key == key);
 
-					var tmp_bomList = bomList.FindAll(t => t.pzid == pzid);
-                    if (tmp_bomList.Count > 0)
+                if (existingItem.Equals(default(KeyValuePair<string, List<u_softbed_mx>>)))
+                {
+                    var newMxList = new List<u_softbed_mx> { mx };
+                    typeList.Add(new KeyValuePair<string, List<u_softbed_mx>>(key, newMxList));
+                }
+                else
+                {
+                    existingItem.Value.Add(mx);
+                }
+
+                if (mx.pzid == 0)
+                {
+                    pzid0List.Add(mx);
+                }
+            }
+            var bomDict = new Dictionary<string, List<u_softbed_mx>>();
+            foreach (var bom in bomList)
+            {
+                var key = $"{bom.has_type}|{bom.pzid}";
+                if (!bomDict.ContainsKey(key))
+                {
+                    bomDict.Add(key, new List<u_softbed_mx>());
+                }
+                bomDict[key].Add(bom);
+            }
+            /**
+			 * 1、模板报价
+			 * 2、非模板报价
+			 * 仅替换配置,保留其他明细信息
+			 * 1、如果明细存在bomList中,证明没有替换,直接添加到newList
+			 * 2、如果明细不存在bomList中,证明可能是给替换的(2.1)或者是非部件(即手动添加2.2)
+			 */
+            foreach (var kvp in typeList)
+            {
+                if (bomDict.TryGetValue(kvp.Key, out var temp_bomList))
+                {
+                    bool isExist = false;
+                    foreach (var mx in kvp.Value)
+                    {
+                        isExist = temp_bomList.FindIndex(t => t.mtrlid == mx.mtrlid) > -1;
+                    }
+                    if (isExist)
                     {
-                        // add
-                        foreach (var temp in tmp_bomList)
+                        // 1
+                        foreach (var mx in kvp.Value)
                         {
-                            if (temp.mtrlid == mx.mtrlid)
-                            {
-                                mx.printid = newList.Count + 1;
-                                newList.Add(mx);
-                            }
-                            else
-                            {
-                                temp.printid = newList.Count + 1;
-                                newList.Add(temp);
-                            }
+							mx.printid = newList.Count + 1;
+							newList.Add(mx);
                         }
                     }
+                    else
+                    {
+                        // 2.1
+                        foreach (var mx in temp_bomList)
+                        {
+                            mx.printid = newList.Count + 1;
+                            newList.Add(mx);
+                        }
+                    }
+                    bomDict.Remove(kvp.Key);
                 }
-			}
-
+            }
+            // 新增的部件
+            foreach (var item in bomDict)
+			{
+                foreach (var mx in item.Value)
+                {
+                    mx.printid = newList.Count + 1;
+                    newList.Add(mx);
+                }
+            }
+            // 2.2
+            foreach (var mx in pzid0List)
+            {
+                mx.printid = newList.Count + 1;
+                newList.Add(mx);
+            }
 			if (newList.Count <= 0) newList.AddRange(bomList);
 			return newList;
         }
@@ -202,7 +210,7 @@ namespace JLHHJSvr.Helper
 				var resultList = new List<u_configure_codemxbom>();
 				var outputFields = @"pzid,printid,pid,mtrlid,sonscale,sonscale_formula,mng_cost_rate,profit_rate,realqty,cost,sonloss,sonloss_formula,
 									sondecloss,sondecloss_formula,default_length,default_width,default_qty,mtrlcode,mtrlname,mtrlmode,unit,
-									mtrlsectype,zxmtrlmode,usermtrlmode,price";
+									mtrlsectype,zxmtrlmode,usermtrlmode,price,pzname";
 				var selectStr = @"SELECT u_configure_codemxbom.pzid
 										,u_configure_codemxbom.printid
 										,u_configure_codemxbom.pid
@@ -228,7 +236,10 @@ namespace JLHHJSvr.Helper
 										,u_mtrldef.zxmtrlmode
 										,u_mtrldef.usermtrlmode
 										,u_erpmtrl_price.price
+										,u_configure_codemx.namemx AS pzname
 									FROM u_configure_codemxbom
+									INNER JOIN u_configure_codemx ON u_configure_codemxbom.pzid = u_configure_codemx.pzid
+										AND u_configure_codemxbom.printid = u_configure_codemx.printid
 									INNER JOIN u_mtrldef ON u_configure_codemxbom.mtrlid = u_mtrldef.mtrlid
 									LEFT OUTER JOIN u_erpmtrl_price ON u_configure_codemxbom.mtrlid = u_erpmtrl_price.mtrlid";
 				DbSqlHelper.SelectJoin(cmd,selectStr, 
@@ -272,7 +283,8 @@ namespace JLHHJSvr.Helper
 				actual_useqty = 0,
 				loss_rate = bomItem.sonloss,
 				cost_price = 0,
-				cost_amt = 0
+				cost_amt = 0,
+				pzname = bomItem.pzname
 			};
 			return mx;
         }
@@ -289,18 +301,20 @@ namespace JLHHJSvr.Helper
 			foreach(var mx in softbed.mxList)
 			{
 				AutoInit.AutoInitS(mx);
-			}
 
+                if (mx.has_type != 8) mx.parts_type = string.Empty;
+                else if (string.IsNullOrEmpty(mx.parts_type)) throw new LJCommonException($"明细行:{mx.printid},存在其他配件明细未设置配件类型,请检查!");
+			}
 			// 计算价格
 			CalCulateFormula(softbed);
-            //
+            // 
             var dtNow = context.opdate;
 			var fields = @"softbed_relcode,softbed_name,deptid,mtrlmode,mtrltype,has_headboard,has_nightstand,has_bedframe,is_template,
                             template_id,template_code,template_name,commission,taxes,taxrate,other_rate,extras_cost,money_type,moneyrate,dscrp,costamt,nottax_factory_cost,nottax_dept_cost,
                             dept_cost,foreign_cost,total_mtrl_cost,total_hr_cost,total_cost,version";
 
 			var mx_fields = @"softbed_id,printid,pzid,formulaid,mtrlid,mtrlname,mtrlcode,mtrlmode,unit,has_type,allow_edit,cutting_length,cutting_width,cutting_qty,
-							useqty,use_formula,use_formula_str,actual_useqty,loss_rate,price,price_formula,price_formula_str,cost_price,cost_amt";
+							useqty,use_formula,use_formula_str,actual_useqty,loss_rate,price,price_formula,price_formula_str,cost_price,cost_amt,parts_type,pzname";
 
 			if(softbed.softbed_id == 0)
 			{
@@ -406,8 +420,8 @@ namespace JLHHJSvr.Helper
 					{
 						throw new LJCommonException($"保存失败,原因:{configureList[mx.has_type].contfigtypename}没有设置物料清单");
 					}
-					var cnt = bomList.Where(t => t.has_type == mx.has_type && t.mtrlid == mx.mtrlid).Count();
-					if (cnt > 1) throw new LJCommonException($"保存失败,原因:{configureList[mx.has_type].contfigtypename}的{mx.mtrlname}存在多个清单,但没有设置部件!");
+					//var cnt = bomList.Where(t => t.has_type == mx.has_type && t.mtrlid == mx.mtrlid).Count();
+					//if (cnt > 1) throw new LJCommonException($"保存失败,原因:{configureList[mx.has_type].contfigtypename}的{mx.mtrlname}存在多个清单,但没有设置部件!");
 					//else if (cnt == 0) throw new LJCommonException($"保存失败,原因:{configureList[mx.has_type].contfigtypename}的{mx.mtrlname}不存在于物料清单中,请检查!");
                 }
             }
@@ -542,7 +556,11 @@ namespace JLHHJSvr.Helper
             {
                 // 模版配置获取
 				int billid = softbed.softbed_id > 0 ? softbed.softbed_id : softbed.template_id;
-                var _softbed = GetSoftBed(billid, "softbed_id,softbed_code,has_headboard,has_nightstand,has_bedframe");
+                var _softbed = GetSoftBed(billid, "softbed_id,softbed_code,has_headboard,has_nightstand,has_bedframe,template_id,is_template");
+				if(_softbed.is_template == 0)
+				{
+                    _softbed = GetSoftBed(_softbed.template_id, "softbed_code,has_headboard,has_nightstand,has_bedframe");
+                }
                 string prefix = $"{_softbed.softbed_code}|";
 
 				if(_softbed.has_headboard == 1)
@@ -621,26 +639,31 @@ namespace JLHHJSvr.Helper
 		/// </summary>
 		/// <param name="softbed"></param>
 		/// <param name="newId"></param>
-        public void CopySoftBed(u_softbed softbed, out int newId)
+        public u_softbed CopySoftBed(u_softbed softbed)
         {
-			var fields = @"mtrlmode,mtrltype,has_headboard,has_nightstand,has_bedframe,is_template,
-                            template_id,template_code,template_name,commission,taxes,taxrate,other_rate,extras_cost,moneyrate";
-            var softbed_copy = GetSoftBed(softbed.softbed_id, fields);
-
+            var softbed_copy = ObjectHelper.DeepCopy(softbed);
+            softbed_copy.softbed_id = 0;
+            SaveSoftBed(softbed_copy);
 
-            // 判断copy_bedNet.bednetcode是否存在@@字符串,如果存在,则删除@@后面的字符串,包括@@
-            if (softbed_copy.softbed_code.IndexOf("@@") > -1)
+            if(softbed_copy.is_template == 1 && softbed.copy_id > 0)
             {
-                softbed_copy.softbed_code = softbed_copy.softbed_code.Substring(softbed_copy.softbed_code.IndexOf("@@"));
+                // 复制配置到新配置
+                var _softbed = GetSoftBed(softbed.copy_id, "softbed_code,has_headboard,has_nightstand,has_bedframe");
+                if(_softbed.has_headboard == 1 && softbed_copy.has_headboard == 1)
+                {
+                    CopyConfigureData($"{_softbed.softbed_code}|床头",$"{softbed_copy.softbed_code}|床头");
+                }
+                if (_softbed.has_nightstand == 1 && softbed_copy.has_nightstand == 1)
+                {
+                    CopyConfigureData($"{_softbed.softbed_code}|床头柜", $"{softbed_copy.softbed_code}|床头柜");
+                }
+                if (_softbed.has_bedframe == 1 && softbed_copy.has_bedframe == 1)
+                {
+                    CopyConfigureData($"{_softbed.softbed_code}|床架", $"{softbed_copy.softbed_code}|床架");
+                }
             }
 
-            softbed_copy.softbed_code += " @@";
-            softbed_copy.softbed_code += DateTime.Now.ToString("yyyMMdd_mmhhss");
-            softbed_copy.softbed_id = 0;
-
-            SaveSoftBed(softbed_copy);
-
-            newId = softbed_copy.softbed_id;
+            return softbed_copy;
         }
 
         /// <summary>
@@ -847,6 +870,108 @@ namespace JLHHJSvr.Helper
 			}
         }
 
+        private List<string> GetConfigureTypeNameFromBillId(int billid)
+        {
+            var _softbed = GetSoftBed(billid, "softbed_code,has_headboard,has_nightstand,has_bedframe");
+
+            var nameList = new List<string>();
+            string prefix = $"{_softbed.softbed_code}|";
+            if (_softbed.has_headboard == 1)
+            {
+                nameList.Add($"{_softbed.softbed_code}|床头");
+            }
+            if (_softbed.has_nightstand == 1)
+            {
+                nameList.Add($"{_softbed.softbed_code}|床头柜");
+            }
+            if (_softbed.has_bedframe == 1)
+            {
+                nameList.Add($"{_softbed.softbed_code}|床架");
+            }
+
+            return nameList;
+        }
+
+        private void CopyConfigureData(string SourceName, string TargetName)
+        {
+            var commonHelper = GetHelper<CommonHelper>(cmd, context);
+            var basicInfoHelper = GetHelper<BasicInfoHelper>(cmd, context);
+            // 入参非空验证
+            if (string.IsNullOrWhiteSpace(SourceName))
+            {
+                throw new LJCommonException("源配置名称不能为空");
+            }
+
+            if (string.IsNullOrWhiteSpace(TargetName))
+            {
+                throw new LJCommonException("目标配置名称不能为空");
+            }
+
+            int SourceId = 0, TargetId = 0;
+            cmd.CommandText = @"SELECT contfigtypeid FROM u_configure_type WHERE LTRIM(RTRIM(contfigtypename)) = LTRIM(RTRIM(@SourceName))";
+            cmd.Parameters.Clear();
+            cmd.Parameters.AddWithValue("@SourceName", SourceName);
+            using(var reader = cmd.ExecuteReader())
+            {
+                if(reader.Read())
+                {
+                    SourceId = Convert.ToInt32(reader["contfigtypeid"]);
+                }
+            }
+
+            cmd.CommandText = @"SELECT contfigtypeid FROM u_configure_type WHERE LTRIM(RTRIM(contfigtypename)) = LTRIM(RTRIM(@TargetName))";
+            cmd.Parameters.Clear();
+            cmd.Parameters.AddWithValue("@TargetName", TargetName);
+            using (var reader = cmd.ExecuteReader())
+            {
+                if (reader.Read())
+                {
+                    TargetId = Convert.ToInt32(reader["contfigtypeid"]);
+                }
+            }
+
+            if (SourceId == 0) throw new LJCommonException($"源配置名称「{SourceName.Trim()}」未找到对应的结果");
+            if (TargetId == 0) throw new LJCommonException($"目标配置名称「{TargetName.Trim()}」未找到对应的结果");
+            // 部件选配项
+            var codeList = commonHelper.ExecuteDynamicSelectToList<u_configure_code>("web_configure_codelist",new Newtonsoft.Json.Linq.JObject() { { "typeid",SourceId} },0,0);
+            var code_copyList = new List<u_configure_code>();
+            var codeIdMap = new Dictionary<int, int>();
+            foreach(var code in codeList)
+            {
+                var code_copy = ObjectHelper.DeepCopy(code);
+                code_copy.pzid = BllHelper.GetID(cmd, "u_configure_code");
+                code_copy.typeid = TargetId;
+                code_copyList.Add(code_copy);
+
+                if (codeIdMap.ContainsKey(code.pzid.Value)) continue;
+                codeIdMap.Add(code.pzid.Value, code_copy.pzid.Value);
+                //basicInfoHelper.SaveConfigureCode(code_copy);
+            }
+            DbSqlHelper.BulkInsert(cmd, code_copyList, "u_configure_code", null, "typeid,pzid,pzcode,inputtype,name,configtype,ifcross,ifcheck,ifuse,rulestr,ifnum,decnum,maxnum,minnum,pricestr,priceratestr,ifpack,zj_special");
+            // 部件选配值
+            var codeMxList = commonHelper.ExecuteDynamicSelectToList<u_configure_codemx>("web_configure_codemxlist", new Newtonsoft.Json.Linq.JObject() { { "typeid", SourceId } }, 0, 0);
+            var codeMx_copyList = new List<u_configure_codemx>();
+            foreach (var codeMx in codeMxList)
+            {
+                if (!codeIdMap.TryGetValue(codeMx.pzid.Value, out int newId)) continue;
+                var codeMx_copy = ObjectHelper.DeepCopy(codeMx);
+                codeMx_copy.pzid = newId;
+                codeMx_copyList.Add(codeMx_copy);
+            }
+            DbSqlHelper.BulkInsert(cmd, codeMx_copyList, "u_configure_codemx",null, "pzid,printid,pzcodemx,namemx,gradestr,mtrlcode,price,ifdft,MCostRate,ProfitRate,dscrp,ifuse,ifnoch,pricerate,packqty,packvol,price_pz,grade");
+            // 部件选配物料清单
+            var codeMxBomList = commonHelper.ExecuteDynamicSelectToList<u_configure_codemxbom>("web_configure_codemxbomlist", new Newtonsoft.Json.Linq.JObject() { { "typeid", SourceId } }, 0, 0);
+            var codeMxBom_copyList = new List<u_configure_codemxbom>();
+            foreach (var codeMxBom in codeMxBomList)
+            {
+                if (!codeIdMap.TryGetValue(codeMxBom.pzid, out int newId)) continue;
+                var codeMxBom_copy = ObjectHelper.DeepCopy(codeMxBom);
+                codeMxBom_copy.pzid = newId;
+                codeMxBom_copyList.Add(codeMxBom_copy);
+            }
+            DbSqlHelper.BulkInsert(cmd, codeMxBom_copyList, "u_configure_codemxbom",null, "pzid,printid,pid,mtrlid,sonscale,sonscale_formula,mng_cost_rate,profit_rate,realqty,sonloss,sonloss_formula,sondecloss,sondecloss_formula,default_length,default_width,default_qty");
+        }
+
         #region 通用公式
         private CalculateFormula formula = new CalculateFormula();
 		private string BillKeyWord = "u_softbed";

+ 1 - 0
JLHHJSvr/JLHHJSvr.csproj

@@ -485,6 +485,7 @@
     <Compile Include="Helper\BasicInfoHelper.cs" />
     <Compile Include="Helper\BedNetHelper.cs" />
     <Compile Include="Helper\CacheHelper.cs" />
+    <Compile Include="Helper\CommonHelper.cs" />
     <Compile Include="Helper\ERPHelper.cs" />
     <Compile Include="Helper\InterfaceHelper.cs" />
     <Compile Include="Helper\LockHelper.cs" />

+ 8 - 2
JLHWEB/src/api/interface/index.ts

@@ -1422,12 +1422,17 @@ export namespace Mattress {
 export namespace SoftBed {
   export interface ReqSoftBed {
     softbed: any;
+    type?: string;
   }
   export interface ResSoftBed {
     softbed: any;
     mxList: any[];
     typeList: any[];
   }
+  export interface ReqSoftBedCommonOperate {
+    list?: any[];
+    type?: number;
+  }
   export interface ResGetSoftBedMxList {
     billid: number;
   }
@@ -1435,7 +1440,8 @@ export namespace SoftBed {
     typeList: any[];
   }
   export interface ReqGetChangeSoftBedMxList {
-    billid: number;
-    codeList: any[];
+    billid?: number;
+    mxList?: any[];
+    codeList?: any[];
   }
 }

+ 4 - 4
JLHWEB/src/api/modules/quote.ts

@@ -250,21 +250,21 @@ export const SaveBedNetInterface = (params: Mattress.ReqSaveMattressInterface) =
 /**
  * @name 软床报价:保存/修改
  */
-export const SaveSoftBedQuote = (params: Mattress.ReqSaveMattressInterface) => {
-  return http.post<Mattress.ResSaveMattressBcp>(PORT1 + `/SaveSoftBedQuote`, params);
+export const SaveSoftBedQuote = (params: SoftBed.ReqSoftBed) => {
+  return http.post<SoftBed.ResSoftBed>(PORT1 + `/SaveSoftBedQuote`, params);
 };
 
 /**
  * @name 软床报价:删除
  */
-export const DeleteSoftBedQuote = (params: Mattress.ReqMultiMattressBcp) => {
+export const DeleteSoftBedQuote = (params: SoftBed.ReqSoftBedCommonOperate) => {
   return http.post(PORT1 + `/DeleteSoftBedQuote`, params);
 };
 
 /**
  * @name 软床报价:审核
  */
-export const AuditSoftBedQuote = (params: Mattress.ReqMultiMattressBcp) => {
+export const AuditSoftBedQuote = (params: SoftBed.ReqSoftBedCommonOperate) => {
   return http.post(PORT1 + `/AuditSoftBedQuote`, params);
 };
 

+ 46 - 2
JLHWEB/src/views/quote/softbedQuote/detail.vue

@@ -75,6 +75,27 @@
         </template>
       </LjVxeTable>
     </template>
+    <template #Other>
+      <LjVxeTable
+        ref="VxeTableOtherMxRef"
+        row-key="key"
+        table-cls="h-full"
+        :data="otherMx"
+        :columns="columnsMxOther"
+        :dwname="DwnameEnum.softbedQuoteMx"
+        :table-props="tableProps_mx"
+        :tool-button="[]"
+        :auto-load-layout="false"
+        :request-auto="false"
+      >
+        <template #tableHeader>
+          <el-space wrap v-if="orderStatus">
+            <el-button type="primary" @click="toAddMx(VxeTableOtherMxRef)">{{ t("common.addText") }}</el-button>
+            <el-button type="danger" @click="toDelMx(VxeTableOtherMxRef)">{{ t("common.delText") }}</el-button>
+          </el-space>
+        </template>
+      </LjVxeTable>
+    </template>
   </LjDetail>
   <BedConfigModal
     v-model="isModalVisible"
@@ -125,10 +146,13 @@ const {
   sharedFormulaEditorRef,
   columns,
   columnsMx,
+  columnsMxOther,
   softBed,
   headBoardMx,
   nightStandMx,
   bedFrameMx,
+  otherMx,
+  VxeTableOtherMxRef,
   isModalVisible,
   showHeadboard,
   showBedframe,
@@ -151,6 +175,7 @@ const {
   onDelete,
   onConfirmConfigureDialog,
   GetSoftBedFormulaMapper,
+  GetSoftBedAccessoryMapper,
   openSharedFormulaEditor,
   handleFormulaConfirm
 } = useHooks(t);
@@ -273,6 +298,11 @@ const detailProps = reactive<DetailProp>({
         if (!params) return true;
         return params?.has_bedframe === 0;
       }
+    },
+    {
+      id: "Other",
+      type: "table",
+      label: "其他"
     }
   ]
 });
@@ -317,11 +347,24 @@ const orderDefaultAction = [
       return "";
     },
     clickFunc: () => {
+      loadingStatus.save = true;
       onSave(res => {
+        loadingStatus.save = false;
         if (res.softbed.softbed_id) {
-          router.replace(`/softbedQuote/detail?id=${res.softbed.softbed_id}&code=${res.softbed.softbed_code}`);
+          pageRefresh({
+            name: "softbedQuoteDetail",
+            params: {
+              id: res.softbed.softbed_id,
+              code: res.softbed.softbed_code
+            },
+            query: {
+              id: res.softbed.softbed_id,
+              code: res.softbed.softbed_code,
+              fromCopySave: orderStatus.value == "copy"
+            }
+          });
         } else {
-          router.replace("/softbedQuote");
+          router.replace("/softbedQuote/index");
         }
       });
     }
@@ -473,6 +516,7 @@ const funcAfterMound = async (data: any) => {
 
 onMounted(() => {
   GetSoftBedFormulaMapper();
+  GetSoftBedAccessoryMapper();
 });
 
 // 返回绑定的事件

+ 430 - 77
JLHWEB/src/views/quote/softbedQuote/hooks/index.tsx

@@ -73,6 +73,14 @@ interface defaultState {
    * @description 详情页主表明细数据-床架
    */
   bedFrameMx: any[];
+  /**
+   * @description 详情页主表明细数据-其他
+   */
+  otherMx: any[];
+  /**
+   * @description 详情页明细表格Ref-其他
+   */
+  VxeTableOtherMxRef: any;
   /**
    * @description 详情页模板报价弹窗对象
    */
@@ -106,6 +114,7 @@ interface defaultState {
   ErpMtrlPriceDialogProps: any;
   softBedFormulaEnum: any[];
   deptEnum: any[];
+  accessoryEnum: any[];
 }
 
 /**
@@ -120,6 +129,7 @@ export const useHooks = (t?: any) => {
     VxeTableHeadBoardMxRef: null,
     VxeTableBedFrameMxRef: null,
     VxeTableNightStandMxRef: null,
+    VxeTableOtherMxRef: null,
     formulaEditorRef: null,
     currentEditRow: null,
     currentEditCol: null,
@@ -128,6 +138,7 @@ export const useHooks = (t?: any) => {
     headBoardMx: [],
     nightStandMx: [],
     bedFrameMx: [],
+    otherMx: [],
     SoftBedTemplateDialogRef: null,
     SoftBedTemplateDialogProps: null,
     isModalVisible: false,
@@ -147,7 +158,8 @@ export const useHooks = (t?: any) => {
     ErpMtrlPriceDialogRef: null,
     ErpMtrlPriceDialogProps: {},
     softBedFormulaEnum: [],
-    deptEnum: []
+    deptEnum: [],
+    accessoryEnum: []
   });
   // 表格配置项
   const columns: ColumnProps<any>[] = [
@@ -869,6 +881,282 @@ export const useHooks = (t?: any) => {
             v-model={row.pzname}
             disabled={_disabled}
             clearable={true}
+            value-key={"pzname"}
+            fetch-suggestions={(queryString, cb) => {
+              const results =
+                state[targetArray]?.filter(item => item.pzname?.toLowerCase().includes(queryString.toLowerCase())) || [];
+              cb(results);
+            }}
+            onSelect={val => fModelChosePzName(row, val)}
+          />
+        );
+      }
+    },
+    {
+      field: "formulaname",
+      title: "公式名",
+      width: 160,
+      enum: async () => {
+        const data = (await GetSoftBedFormulaMapper()).datatable.map(t => {
+          return { ...t, label: t.formulaname, value: t.formulaid };
+        });
+        state.softBedFormulaEnum = data;
+        return { data };
+      },
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { row } = scope;
+        const { _mainData } = state.LjDetailRef;
+        const _disabled = !row.allow_edit && !_mainData.is_template;
+
+        const options =
+          state.softBedFormulaEnum?.map(item => <el-option key={item.formulaid} label={item.formulaname} value={item} />) || [];
+
+        return (
+          <el-select
+            v-model={row.formulaname}
+            disabled={_disabled}
+            valueKey={"formulaid"}
+            clearable={true}
+            onChange={val => fModelChoseFormula(row, val)}
+          >
+            {options}
+          </el-select>
+        );
+      }
+    },
+    {
+      field: "mtrlcode",
+      title: "物料编码"
+    },
+    {
+      field: "mtrlname",
+      title: "物料名称规格",
+      width: 300,
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        const { _mainData } = state.LjDetailRef;
+        let _label = column.title;
+        let params = {
+          keyword: row.mtrlcode
+        };
+        const _disabled = !row.allow_edit && !_mainData.is_template;
+
+        return (
+          <ErpMtrlPriceSelect
+            value={row.mtrlid}
+            {...params}
+            clearable
+            disabled={_disabled}
+            placeholder={_label}
+            onOpenModal={() => fModelChoseMtrlErp(row, params)}
+            onSelect={val => rModelSetMtrlErp(row, val)}
+            onClear={() => rModelClearMtrlErp(row)}
+          >
+            {{
+              label: () => `${row.mtrlname} ${row.mtrlmode}`
+            }}
+          </ErpMtrlPriceSelect>
+        );
+      }
+    },
+    {
+      field: "unit",
+      title: "物料单位"
+    },
+    {
+      field: "cutting_length",
+      title: "下料长(mm)",
+      datatype: "number",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        const { _mainData } = state.LjDetailRef;
+
+        let _disabled = !Boolean(row.allow_edit) && !Boolean(_mainData.is_template);
+        return <el-input v-model={scope.row.cutting_length} type="number" disabled={_disabled}></el-input>;
+      }
+    },
+    {
+      field: "cutting_width",
+      title: "下料宽(mm)",
+      datatype: "number",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        const { _mainData } = state.LjDetailRef;
+
+        let _disabled = !Boolean(row.allow_edit) && !Boolean(_mainData.is_template);
+        return <el-input v-model={scope.row.cutting_width} type="number" disabled={_disabled}></el-input>;
+      }
+    },
+    {
+      field: "cutting_qty",
+      title: "下料数量",
+      datatype: "number",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        const { _mainData } = state.LjDetailRef;
+
+        let _disabled = !Boolean(row.allow_edit) && !Boolean(_mainData.is_template);
+        return <el-input v-model={scope.row.cutting_qty} type="number" disabled={_disabled}></el-input>;
+      }
+    },
+    {
+      field: "useqty",
+      title: "理论用料量",
+      datatype: "number",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        const { _mainData } = state.LjDetailRef;
+
+        let _disabled = !Boolean(row.allow_edit) && !Boolean(_mainData.is_template);
+        return <el-input v-model={scope.row.useqty} type="number" disabled={_disabled}></el-input>;
+      }
+    },
+    {
+      field: "use_formula",
+      title: "用料量公式",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        return (
+          <el-input
+            v-model={scope.row.use_formula}
+            readonly
+            placeholder="点击编辑公式"
+            onClick={() => openSharedFormulaEditor(scope.row.use_formula, row, column)}
+          />
+        );
+      }
+    },
+    {
+      field: "use_formula_str",
+      title: "用料量文本公式"
+    },
+    {
+      field: "actual_useqty",
+      title: "实际用量",
+      datatype: "number"
+    },
+    {
+      field: "loss_rate",
+      title: "损耗率",
+      datatype: "number",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        const { _mainData } = state.LjDetailRef;
+
+        let _disabled = !Boolean(row.allow_edit) && !Boolean(_mainData.is_template);
+        return <el-input v-model={scope.row.loss_rate} type="number" disabled={_disabled}></el-input>;
+      }
+    },
+    {
+      field: "price",
+      title: "材料单价",
+      datatype: "number",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        const { _mainData } = state.LjDetailRef;
+
+        let _disabled = !Boolean(row.allow_edit) && !Boolean(_mainData.is_template);
+        return <el-input v-model={scope.row.price} type="number" disabled={_disabled}></el-input>;
+      }
+    },
+    {
+      field: "price_formula",
+      title: "单价公式",
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { $table, column, row, status } = scope;
+        return (
+          <el-input
+            v-model={scope.row.price_formula}
+            readonly
+            placeholder="点击编辑公式"
+            onClick={() => openSharedFormulaEditor(scope.row.price_formula, row, column)}
+          />
+        );
+      }
+    },
+    {
+      field: "price_formula_str",
+      title: "单价文本公式"
+    },
+    {
+      field: "cost_price",
+      title: "成本单价",
+      datatype: "number"
+    },
+    {
+      field: "cost_amt",
+      title: "成本金额",
+      datatype: "number"
+    }
+  ];
+
+  // 其他tab页明细表格配置项(包含配件列)
+  const columnsMxOther: ColumnProps<any>[] = [
+    {
+      field: "printid",
+      title: "行号",
+      width: 50
+    },
+    {
+      field: "parts_type",
+      title: "配件",
+      width: 120,
+      enum: async () => {
+        const data = (await GetSoftBedAccessoryMapper()).datatable;
+        state.accessoryEnum = data.map((t: any) => {
+          return { label: t.label, value: t.value };
+        });
+        return state.accessoryEnum;
+      },
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { row } = scope;
+        const { _mainData } = state.LjDetailRef;
+        const _disabled = !row.allow_edit && !_mainData.is_template;
+
+        const options =
+          state.accessoryEnum?.map(item => <el-option key={item.label} label={item.label} value={item.label} />) || [];
+
+        return (
+          <el-select v-model={row.parts_type} disabled={_disabled} clearable={true} placeholder="请选择配件类型">
+            {options}
+          </el-select>
+        );
+      }
+    },
+    {
+      field: "pzname",
+      title: "部件选配项",
+      width: 160,
+      editRender: {},
+      editColRender: (scope: any) => {
+        const { row } = scope;
+        const { _mainData } = state.LjDetailRef;
+        const _disabled = !row.allow_edit && !_mainData.is_template;
+
+        const partTypes = {
+          1: "headboardConfigOptions",
+          2: "nightstandConfigOptions",
+          8: "bedframeConfigOptions"
+        };
+        const targetArray = partTypes[row.has_type] || "headboardConfigOptions";
+        // const options = state[targetArray]?.map(item => <el-option key={item.pzid} label={item.pzname} value={item} />) || [];
+        return (
+          <el-autocomplete
+            v-model={row.pzname}
+            disabled={_disabled}
+            clearable={true}
+            value-key={"pzname"}
             fetch-suggestions={(queryString, cb) => {
               const results =
                 state[targetArray]?.filter(item => item.pzname?.toLowerCase().includes(queryString.toLowerCase())) || [];
@@ -1098,6 +1386,7 @@ export const useHooks = (t?: any) => {
 
     const result = await GetSoftBedMxList(params);
     if (state.orderStatus === "copy") {
+      result.softbed.copy_id = result.softbed.softbed_id;
       result.softbed.softbed_id = 0;
       result.softbed.softbed_code = "";
     }
@@ -1106,6 +1395,7 @@ export const useHooks = (t?: any) => {
     state.headBoardMx = result.mxList.filter(item => item.has_type === 1);
     state.nightStandMx = result.mxList.filter(item => item.has_type === 2);
     state.bedFrameMx = result.mxList.filter(item => item.has_type === 4);
+    state.otherMx = result.mxList.filter(item => item.has_type === 8);
   };
   /**
    * 打开部件配置弹窗
@@ -1154,7 +1444,7 @@ export const useHooks = (t?: any) => {
             state.configValueOptionsMap[code.pzid].push(...code.codeMxList.filter(t => t.pzid === code.pzid));
 
             // 自动添加标准选配值
-            if (targetConfig && targetConfig.length <= 0) {
+            if (targetConfig.findIndex(t => t.pzid === code.pzid) === -1) {
               targetConfig.push(
                 ...code.codeMxList
                   .filter(t => t.ifdft === 1)
@@ -1172,88 +1462,74 @@ export const useHooks = (t?: any) => {
    * 确认部件配置项值
    * @param params 返回内容
    */
-  const onConfirmConfigureDialog = async (params: any) => {
+  const onConfirmConfigureDialog = (params: any) => {
     const { _mainData } = state.LjDetailRef;
+    const { fullData: headboard_table } = state.VxeTableHeadBoardMxRef?.element.getTableData();
+    const { fullData: nightstand_table } = state.VxeTableNightStandMxRef?.element.getTableData();
+    const { fullData: bedframe_table } = state.VxeTableBedFrameMxRef?.element.getTableData();
 
-    nextTick(() => {
+    nextTick(async () => {
       _mainData.has_headboard = Number(state.showHeadboard);
       _mainData.has_nightstand = Number(state.showNightstand);
       _mainData.has_bedframe = Number(state.showBedframe);
 
       state.isModalVisible = false;
-    });
-
-    const _codeMxList = [];
-    if (_mainData.has_headboard) {
-      _codeMxList.push(
-        ...state.partsConfig.headboard.map(t => {
-          return { pzid: t.pzid, printid: t.selectedId, has_type: 1 };
-        })
-      );
-    }
-    if (_mainData.has_nightstand) {
-      _codeMxList.push(
-        ...state.partsConfig.nightstand.map(t => {
-          return { pzid: t.pzid, printid: t.selectedId, has_type: 2 };
-        })
-      );
-    }
-    if (_mainData.has_bedframe) {
-      _codeMxList.push(
-        ...state.partsConfig.bedframe.map(t => {
-          return { pzid: t.pzid, printid: t.selectedId, has_type: 4 };
-        })
-      );
-    }
 
-    const billid = _mainData.template_id > 0 ? Number(_mainData.template_id) : Number(_mainData.softbed_id);
-    const result = await GetChangeSoftBedMxList({ billid, codeList: _codeMxList });
-    const copyMap = new Map();
-    const { fullData: headboard_table } = state.VxeTableHeadBoardMxRef?.element.getTableData();
-    const { fullData: nightstand_table } = state.VxeTableNightStandMxRef?.element.getTableData();
-    const { fullData: bedframe_table } = state.VxeTableBedFrameMxRef?.element.getTableData();
-    headboard_table?.forEach(mx => {
-      copyMap.set(`${mx.has_type}|${mx.pzid}|${mx.mtrlid}`, mx);
-    });
-    nightstand_table?.forEach(mx => {
-      copyMap.set(`${mx.has_type}|${mx.pzid}|${mx.mtrlid}`, mx);
-    });
-    bedframe_table?.forEach(mx => {
-      copyMap.set(`${mx.has_type}|${mx.pzid}|${mx.mtrlid}`, mx);
-    });
-
-    const newHeadBoardMx = [];
-    const newNightStandMx = [];
-    const newBedFrameMx = [];
-    result.mxList.forEach(mx => {
-      const key = `${mx.has_type}|${mx.pzid}|${mx.mtrlid}`;
-      if (copyMap.has(key)) {
-        // matchQty++;
-        const mx2 = copyMap.get(key);
-        mx = mx2;
-        // mx.haschange = 1;
+      const _codeMxList = [];
+      if (_mainData.has_headboard) {
+        _codeMxList.push(
+          ...state.partsConfig.headboard.map(t => {
+            return { pzid: t.pzid, printid: t.selectedId, has_type: 1 };
+          })
+        );
+      }
+      if (_mainData.has_nightstand) {
+        _codeMxList.push(
+          ...state.partsConfig.nightstand.map(t => {
+            return { pzid: t.pzid, printid: t.selectedId, has_type: 2 };
+          })
+        );
+      }
+      if (_mainData.has_bedframe) {
+        _codeMxList.push(
+          ...state.partsConfig.bedframe.map(t => {
+            return { pzid: t.pzid, printid: t.selectedId, has_type: 4 };
+          })
+        );
       }
 
-      if (mx.has_type === 1) newHeadBoardMx.push(mx);
-      else if (mx.has_type === 2) newNightStandMx.push(mx);
-      else if (mx.has_type === 4) newBedFrameMx.push(mx);
-    });
-
-    state.headBoardMx = newHeadBoardMx;
-    state.nightStandMx = newNightStandMx;
-    state.bedFrameMx = newBedFrameMx;
-
-    if (result.mxList.length > 0) {
-      ElNotification({
-        title: "导入成功",
-        type: "success"
+      const billid = _mainData.template_id > 0 ? Number(_mainData.template_id) : Number(_mainData.softbed_id);
+      const result = await GetChangeSoftBedMxList({
+        billid,
+        mxList: [...headboard_table, ...nightstand_table, ...bedframe_table],
+        codeList: _codeMxList
       });
-    } else {
-      ElNotification({
-        title: "导入失败",
-        type: "warning"
+      const newHeadBoardMx = [];
+      const newNightStandMx = [];
+      const newBedFrameMx = [];
+
+      result.mxList.forEach(mx => {
+        if (mx.has_type === 1) newHeadBoardMx.push(mx);
+        else if (mx.has_type === 2) newNightStandMx.push(mx);
+        else if (mx.has_type === 4) newBedFrameMx.push(mx);
       });
-    }
+
+      state.headBoardMx = newHeadBoardMx;
+      state.nightStandMx = newNightStandMx;
+      state.bedFrameMx = newBedFrameMx;
+
+      if (result.mxList.length > 0) {
+        ElNotification({
+          title: "导入成功",
+          type: "success"
+        });
+      } else {
+        ElNotification({
+          title: "导入失败",
+          type: "warning"
+        });
+      }
+    });
   };
   /**
    * 保存报价
@@ -1264,6 +1540,7 @@ export const useHooks = (t?: any) => {
     const { fullData: headboard_table } = state.VxeTableHeadBoardMxRef?.element.getTableData();
     const { fullData: nightstand_table } = state.VxeTableNightStandMxRef?.element.getTableData();
     const { fullData: bedframe_table } = state.VxeTableBedFrameMxRef?.element.getTableData();
+    const { fullData: other_table } = state.VxeTableOtherMxRef?.element.getTableData();
 
     const _softbed = cloneDeep(_mainData);
     const _mxList = [];
@@ -1274,6 +1551,7 @@ export const useHooks = (t?: any) => {
     if (headboard_table && headboard_table.length > 0) _mxList.push(...headboard_table);
     if (nightstand_table && nightstand_table.length > 0) _mxList.push(...nightstand_table);
     if (bedframe_table && bedframe_table.length > 0) _mxList.push(...bedframe_table);
+    if (other_table && other_table.length > 0) _mxList.push(...other_table);
 
     if (_softbed.has_headboard)
       _codeMxList.push(
@@ -1297,7 +1575,8 @@ export const useHooks = (t?: any) => {
     transformData(_softbed);
 
     const params: any = {
-      softbed: _softbed
+      softbed: _softbed,
+      type: state.orderStatus
     };
 
     try {
@@ -1435,6 +1714,19 @@ export const useHooks = (t?: any) => {
     //   );
     // }
   };
+  /**
+   * 获取配件类型
+   * @returns
+   */
+  const GetSoftBedAccessoryMapper = async () => {
+    const result = await CommonDynamicSelect({ dsname: "_Mapper_softbed_accessory", queryparams: {} });
+    if (result && result.datatable) {
+      state.accessoryEnum = result.datatable.map((item: any) => {
+        return { label: item.label, value: item.value };
+      });
+    }
+    return result;
+  };
   /**
    * @description 获取部门汇率 和  折扣率
    */
@@ -1528,6 +1820,7 @@ export const useHooks = (t?: any) => {
     state.headBoardMx = result.mxList.filter(item => item.has_type === 1);
     state.nightStandMx = result.mxList.filter(item => item.has_type === 2);
     state.bedFrameMx = result.mxList.filter(item => item.has_type === 4);
+    state.otherMx = result.mxList.filter(item => item.has_type === 8);
   };
   /**
    * 清空选择参数
@@ -1550,14 +1843,65 @@ export const useHooks = (t?: any) => {
     if (
       (has_type === 1 && _mainData.has_headboard === 1) ||
       (has_type === 2 && _mainData.has_nightstand === 1) ||
-      (has_type === 4 && _mainData.has_bedframe === 1)
+      (has_type === 4 && _mainData.has_bedframe === 1) ||
+      has_type === 8 // 其他tab页不需要勾选
     ) {
       const $table = tableRef.element;
       if ($table) {
-        // 新增
+        // 获取当前表格数据,计算行号
+        const currentData = $table.getData() || [];
+        let startIndex = 1;
+        if (currentData.length > 0) {
+          // 找到当前最大的行号
+          const maxPrintId = Math.max(...currentData.map((row: any) => row.printid || 0));
+          startIndex = maxPrintId + 1;
+        }
+
+        // 对于其他tab页,检查是否有value=1的配件类型,如果有则自动添加
+        if (has_type === 8) {
+          // 确保配件枚举数据已加载
+          if (state.accessoryEnum.length === 0) {
+            await GetSoftBedAccessoryMapper();
+          }
+
+          // 查找value=1的配件类型
+          const defaultAccessories = state.accessoryEnum.filter(item => item.value === 1);
+          if (defaultAccessories.length > 0) {
+            // 为每个value=1的配件类型添加一行记录
+            for (let i = 0; i < defaultAccessories.length; i++) {
+              const accessory = defaultAccessories[i];
+              const records = {
+                softbed_id: _mainData.softbed_id,
+                has_type: has_type,
+                printid: startIndex + i, // 设置行号
+                mtrlname: "",
+                mtrlcode: "",
+                mtrlmode: "",
+                unit: "",
+                allow_edit: 0,
+                cutting_length: 0,
+                cutting_width: 0,
+                cutting_qty: 0,
+                loss_rate: 0,
+                price: 0,
+                parts_type: accessory.label // 设置配件类型的值
+              };
+              const { row } = await $table.insertAt(records, -1);
+              await $table.setCurrentRow(row);
+            }
+            ElMessage({
+              type: "success",
+              message: `已自动添加 ${defaultAccessories.length} 个默认配件类型`
+            });
+            return;
+          }
+        }
+
+        // 普通新增逻辑
         const records = {
           softbed_id: _mainData.softbed_id,
           has_type: has_type,
+          printid: startIndex, // 设置行号
           mtrlname: "",
           mtrlcode: "",
           mtrlmode: "",
@@ -1567,7 +1911,8 @@ export const useHooks = (t?: any) => {
           cutting_width: 0,
           cutting_qty: 0,
           loss_rate: 0,
-          price: 0
+          price: 0,
+          parts_type: has_type === 8 ? "" : undefined // 其他tab页添加配件列
         };
         const { row } = await $table.insertAt(records, -1);
         await $table.setCurrentRow(row);
@@ -1599,7 +1944,13 @@ export const useHooks = (t?: any) => {
   };
 
   const getHasType = (tableRef: any) => {
-    return tableRef === state.VxeTableHeadBoardMxRef ? 1 : tableRef === state.VxeTableNightStandMxRef ? 2 : 4;
+    return tableRef === state.VxeTableHeadBoardMxRef
+      ? 1
+      : tableRef === state.VxeTableNightStandMxRef
+      ? 2
+      : tableRef === state.VxeTableBedFrameMxRef
+      ? 4
+      : 8;
   };
 
   /**
@@ -1693,6 +2044,7 @@ export const useHooks = (t?: any) => {
     ...toRefs(state),
     columns,
     columnsMx,
+    columnsMxOther,
     detail_getData,
     toAddMx,
     toDelMx,
@@ -1704,6 +2056,7 @@ export const useHooks = (t?: any) => {
     onShowFormula,
     onConfirmConfigureDialog,
     GetSoftBedFormulaMapper,
+    GetSoftBedAccessoryMapper,
     openSharedFormulaEditor,
     handleFormulaConfirm
   };