1 配置
因为本平台功能之一为项目查询用,所以必要的项目信息是必不可少的。
还要区分水利、电力、市政、交通……
2 工程费用表分表问题
建筑工程、临时工程、机电及金属结构安装工程等表,数据是放一个数据表中还是建立对应的不同的数据表?
经过试验,还是分别放比较好。原因是,在下列每个表分级查询的时候,如果在一个表格中,会出现父子级关系错乱。也可能是我的表内父子关联没设计好……
3 工程费用表分级
目前支持6级,即工程费用在4 ~ 6级,前面必须有3级,第一级是专业,例如建筑工程、机电工程……第2级是工程部位,第3级是部位往下细分,第4级是继续细分
水利行业:
电力行业:
4 数据表设计
对于费用表,1 ~ 5级分了3个表,是否必要??第一级和第二级分别各为一个表,3 ~ 5为一个表,因为可能是3级,也可能是4级也可能是5级,不确定。
工程量单价在第4 ~ 6级。
经过对比,还是放一个表比较合理,查询比较方便。
但是对于树状数据的递归查询,似乎没办法做到分页查询?
// 项目表
type EstimateProject struct {
gorm.Model
Number string `json:"number"`
Name string `json:"name"`
Profile string `json:"profile"`
Grade string `json:"grade"`
Period int `json:"period"`
UserID int64
// User User `json:"user" gorm:"foreignKey:UserID;references:Id;"` // 这个写法错误,所以无法建表
}
// 项目——阶段——价格水平
type EstimateProjPhase struct {
gorm.Model
EstimateProjectID uint `json:"estimateprojectid"`
PhaseName string `json:"phasename"` // 项目阶段
Information string `json:"information"` // 价格水平年
TotalInvestment float64 `json:"totalinvestment"` // 总投资
StaticInvestment float64 `json:"staticinvestment"` // 静态投资
}
// 作废!项目——阶段——工程专业部分professional
type EstimateProfessional struct {
gorm.Model
EstimateProjPhaseID uint `json:"estimateprojphaseid"`
Component string `json:"component"`
Total float64 `json:"total"`
}
// 作废!工程专业部分——工程二级Secondary
type EstimateSecondary struct {
gorm.Model
EstimateProfessionalID uint `json:"estimateprofessionalid"`
Number string `json:"number"`
Component string `json:"component"`
Total float64 `json:"total"`
}
// 作废!工程二级——工程三~六级
type EstimateTertiary struct {
gorm.Model
EstimateSecondaryID uint `json:"estimatesecondaryid"`
ParentID uint `json:"parentid"`
Number string `json:"number"`
Component string `json:"component"`
Total float64 `json:"total"`
}
// 费用表
type EstimateCost struct {
gorm.Model
EstimateProjPhaseID uint `json:"estimateprojphaseid"`
ParentID uint `json:"parentid"`
CostName string `json:"costname"`
Unit string `json:"unit"`
Quantity float64 `json:"quantity"`
UnitPrice float64 `json:"unitprice"`
Total float64 `json:"total"`
}
5 解析工程费用表格
第一个功能是实现上传表格,解析表格
利用正则表达式判断级别,对于汉字,要用反引号
和[一-龟]
来判断一二三四五……十一十二十三
……,不要用双引号和[\u4e00-\u9fa5]
来判断中文。因为双引号不支持\( \)
这种括号,而反引号不支持\u4e00
,真是奇葩,所以选择反引号和一-龟
。^[一-龟]{1,2}$
中^
指起始位置,$
指末尾位置
if strings.Contains(sheetname, "建筑") ||
strings.Contains(sheetname, "施工") ||
strings.Contains(sheetname, "临时") ||
strings.Contains(sheetname, "机电") ||
strings.Contains(sheetname, "金结") ||
strings.Contains(sheetname, "金属") {
var partOne bool
// logs.Info(partOne) // false
number := row[0]
costname := row[1]
costname4 := SubString(costname, 0, 4)
// logs.Info(costname4)
//设定一个含有中文的字符串
rex := regexp.MustCompile("^第.部分$")
if rex.MatchString(string(number)) || rex.MatchString(string(costname4)) {
partOne = true
}
if partOne && row[2] == "" && row[3] == "" {
// 一级
// number := row[0]
// costname := row[1]
total := row[5]
totalfloat, err := strconv.ParseFloat(total, 64)
if err != nil {
logs.Error(err)
}
// professionalID, err = models.AddEstimateProfessional(estimatePhaseID, professional_component, totalfloat)
costID, err := models.AddEstimateCost(estimatePhaseID, 0, number, costname, "", 0, 0, totalfloat)
if err != nil {
logs.Error(err)
}
parentID = costID
// break \u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341
} else if regexp.MustCompile(`^[一-龟]{1,2}$`).MatchString(string(row[0])) && row[2] == "" && row[3] == "" && row[4] == "" {
// 二级,类似一 二 三
number := row[0]
secondary_component := row[1]
secondaryID, err = models.AddEstimateSecondary(professionalID, number, secondary_component)
if err != nil {
logs.Error(err)
}
} else if regexp.MustCompile(`^\([一-龟]{1,2}\)$`).MatchString(string(row[0])) && row[2] == "" && row[3] == "" && row[4] == "" {
// 三级,类似(一) (二)
number := row[0]
tertiary_component := row[1]
tertiaryID, err = models.AddEstimateTertiary(secondaryID, parentID, number, tertiary_component)
if err != nil {
logs.Error(err)
}
parentID = tertiaryID
} else if regexp.MustCompile(`^[1-9]\d*$`).MatchString(string(row[0])) && row[2] == "" && row[3] == "" && row[4] == "" {
// 四级,类似1 2 3整数数字
number := row[0]
tertiary_component := row[1]
fourthID, err = models.AddEstimateTertiary(tertiaryID, parentID, number, tertiary_component)
if err != nil {
logs.Error(err)
}
parentID = fourthID
} else if regexp.MustCompile(`^\([1-9]\d*\)$`).MatchString(string(row[0])) && row[2] == "" && row[3] == "" && row[4] == "" {
// 五级,类似(1)(2)带括号的整数数字
number := row[0]
tertiary_component := row[1]
fifthID, err = models.AddEstimateTertiary(fourthID, parentID, number, tertiary_component)
if err != nil {
logs.Error(err)
}
parentID = fifthID
} else if row[1] != "" && row[2] != "" && row[3] != "" && row[4] != "" && row[5] != "" {
// cost表,相当于6级
......
6 解析通用工程单价表
7 查询
有了数据库,接下来就是查询了
7.1 项目列表
一个项目对应多个阶段
7.2 查询得出总概算表来
采用sqlite原生递归语句进行树状数据查询
// 查询某个部位的投资
func GetEstimateCost(estimateProjPhaseID uint, limit, offset int) (estimateCost []EstimateCost, err error) {
db := _db
var q string
q = `
with recursive
tempcost as (
select * from estimate_cost where estimate_proj_phase_id = ?
union all
select estimate_cost.* from tempcost join estimate_cost on tempcost.id = estimate_cost.parent_id
)
select * from tempcost;
`
err = db.Raw(q, estimateProjPhaseID).Scan(&estimateCost).Error
return estimateCost, err
}
查出来的数据需要进行处理:父一级下面紧跟对应的子级……,不然原始查出来的数据是所有父一级在前面,所有子一级紧跟其后……如下图展示的这样:
解决方法是先将查询出来的数据根据parentid父子关系转换成树状json数据,返回给前端,前端用layui treetable来展示树状json数据很方便。如下图:
如何使得treetable展示的树状数据直接全部展开呢,要用done:function(){treetable.expandAll()……
参考上面table的说明文件,在treetable的render里加上done:function……
7.3 查询单价
7.3.1 通用单价法
7.3.2 类比法
最后编辑:秦晓川 更新时间:2024-05-29 09:53