739 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			739 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package project
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"management/internal/db/model/dto"
 | |
| 	formDto "management/internal/db/model/form"
 | |
| 	"management/internal/db/model/view"
 | |
| 	db "management/internal/db/sqlc"
 | |
| 	"management/internal/global"
 | |
| 	"management/internal/global/html"
 | |
| 	"management/internal/middleware/manage/auth"
 | |
| 	"management/internal/pkg/convertor"
 | |
| 	"management/internal/pkg/snowflake"
 | |
| 	"management/internal/router/manage/util"
 | |
| 	projectservice "management/internal/service/project"
 | |
| 	"management/internal/tpl"
 | |
| 
 | |
| 	"github.com/jackc/pgx/v5/pgtype"
 | |
| )
 | |
| 
 | |
| func List(w http.ResponseWriter, r *http.Request) {
 | |
| 	tpl.HTML(w, r, "project/list.tmpl", map[string]any{
 | |
| 		"Statuses": html.NewSelectControls(global.ProjectStatuses, 0),
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func PostList(w http.ResponseWriter, r *http.Request) {
 | |
| 	ctx := r.Context()
 | |
| 	title := strings.TrimSpace(r.PostFormValue("title"))
 | |
| 	var search string
 | |
| 	if len(title) > 0 {
 | |
| 		search = "%" + title + "%"
 | |
| 		if strings.HasSuffix(title, ":") {
 | |
| 			search = title[:len(title)-1] + "%"
 | |
| 		}
 | |
| 	}
 | |
| 	arg := &db.ListProjectConditionParam{
 | |
| 		IsTitle:  len(search) > 0,
 | |
| 		Title:    search,
 | |
| 		Status:   util.ConvertInt16(r.PostFormValue("status"), 9999),
 | |
| 		PageID:   util.ConvertInt32(r.PostFormValue("page"), 1),
 | |
| 		PageSize: util.ConvertInt32(r.PostFormValue("rows"), 10),
 | |
| 	}
 | |
| 	arg.TimeBegin, arg.TimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
 | |
| 	res, total, err := db.Engine.ListProjectCondition(ctx, arg)
 | |
| 	if err != nil {
 | |
| 		http.Error(w, err.Error(), http.StatusInternalServerError)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	data := tpl.ResponseList{
 | |
| 		Code:    0,
 | |
| 		Message: "ok",
 | |
| 		Count:   total,
 | |
| 		Data:    res,
 | |
| 	}
 | |
| 	tpl.JSON(w, data)
 | |
| }
 | |
| 
 | |
| func Add(w http.ResponseWriter, r *http.Request) {
 | |
| 	authUser := auth.AuthUser(r.Context())
 | |
| 	tpl.HTML(w, r, "project/edit.tmpl", map[string]any{
 | |
| 		"Item": &formDto.ProjectForm{
 | |
| 			ApplyUserID: authUser.ID,
 | |
| 			ProjectFiles: &formDto.ProjectFileForm{
 | |
| 				ProjectFileItems: []*formDto.ProjectFileItemForm{},
 | |
| 			},
 | |
| 		},
 | |
| 		"Statuses": html.NewSelectControls(global.ProjectStatuses, 0),
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func Edit(w http.ResponseWriter, r *http.Request) {
 | |
| 	form := &formDto.ProjectForm{}
 | |
| 	id := convertor.ConvertInt[int64](r.URL.Query().Get("id"), 0)
 | |
| 	if id > 0 {
 | |
| 		ctx := r.Context()
 | |
| 		if po, err := db.Engine.GetProject(ctx, id); err == nil {
 | |
| 			pfs, err := db.Engine.ListProjectFiles(ctx, po.ID)
 | |
| 			if err != nil {
 | |
| 				http.Error(w, err.Error(), http.StatusInternalServerError)
 | |
| 				return
 | |
| 			}
 | |
| 			form = form.ToForm(po, pfs)
 | |
| 			if form.ApplyUserID == 0 {
 | |
| 				authUser := auth.AuthUser(ctx)
 | |
| 				form.ApplyUserID = authUser.ID
 | |
| 			}
 | |
| 			if c, err := db.Engine.GetCustomer(ctx, po.CustomerID); err == nil {
 | |
| 				form.CustomerName = c.Name
 | |
| 			}
 | |
| 			// if u, err := db.Engine.GetSysUser(ctx, po.ManagerID); err == nil {
 | |
| 			// 	form.ManagerName = u.Username
 | |
| 			// }
 | |
| 
 | |
| 			// if len(po.Members) > 0 {
 | |
| 			// 	arr := strings.Split(po.Members, ",")
 | |
| 			// 	if len(arr) > 0 {
 | |
| 			// 		var ids []int32
 | |
| 			// 		for _, v := range arr {
 | |
| 			// 			ids = append(ids, convertor.ConvertInt[int32](v, 0))
 | |
| 			// 		}
 | |
| 
 | |
| 			// 		if rows, err := db.Engine.ListSysUserByIds(ctx, ids); err == nil && len(rows) > 0 {
 | |
| 			// 			log.Println("rows: ", rows)
 | |
| 			// 			var names []string
 | |
| 			// 			for _, v := range rows {
 | |
| 			// 				names = append(names, v.Username)
 | |
| 			// 			}
 | |
| 			// 			form.MembersName = strings.Join(names, ",")
 | |
| 			// 		}
 | |
| 			// 	}
 | |
| 			// }
 | |
| 
 | |
| 			// if u, err := db.Engine.GetSysUser(ctx, po.ApplyUserID); err == nil {
 | |
| 			// 	form.ApplyUserName = u.Username
 | |
| 			// }
 | |
| 			if u, err := db.Engine.GetSysUser(ctx, po.CreatedUserID); err == nil {
 | |
| 				form.CreatedName = u.Username
 | |
| 			}
 | |
| 			if u, err := db.Engine.GetSysUser(ctx, po.UpdatedUserID); err == nil {
 | |
| 				form.UpdatedName = u.Username
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	tpl.HTML(w, r, "project/edit.tmpl", map[string]any{
 | |
| 		"Item":     form,
 | |
| 		"Statuses": html.NewSelectControls(global.ProjectStatuses, form.Status),
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func Save(w http.ResponseWriter, r *http.Request) {
 | |
| 	ctx := r.Context()
 | |
| 	form, err := validForm(r)
 | |
| 	if err != nil {
 | |
| 		tpl.JSONERR(w, err.Error())
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	authUser := auth.AuthUser(ctx)
 | |
| 	if form.ID > 0 {
 | |
| 		p := &db.UpdateProjectParams{
 | |
| 			ID: form.ID,
 | |
| 			Name: pgtype.Text{
 | |
| 				String: form.Name,
 | |
| 				Valid:  true,
 | |
| 			},
 | |
| 			StartAt: pgtype.Timestamptz{
 | |
| 				Time:  form.StartAt,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 			EndAt: pgtype.Timestamptz{
 | |
| 				Time:  form.EndAt,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 			CustomerID: pgtype.Int8{
 | |
| 				Int64: form.CustomerID,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 			TotalMoney: form.TotalMoneyF,
 | |
| 			Description: pgtype.Text{
 | |
| 				String: form.Description,
 | |
| 				Valid:  true,
 | |
| 			},
 | |
| 			ApplyAt: pgtype.Timestamptz{
 | |
| 				Time:  form.ApplyAt,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 			ApplyUserID: pgtype.Int4{
 | |
| 				Int32: form.ApplyUserID,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 			ManagerID: pgtype.Int4{
 | |
| 				Int32: form.ManagerID,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 			Members: pgtype.Text{
 | |
| 				String: form.Members,
 | |
| 				Valid:  true,
 | |
| 			},
 | |
| 			Status: pgtype.Int2{
 | |
| 				Int16: form.Status,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 			UpdatedUserID: pgtype.Int4{
 | |
| 				Int32: authUser.ID,
 | |
| 				Valid: true,
 | |
| 			},
 | |
| 		}
 | |
| 		cpfs := []*db.CreateProjectFileParams{}
 | |
| 		for _, pfile := range form.ProjectFiles.ProjectFileItems {
 | |
| 			cpfs = append(cpfs, &db.CreateProjectFileParams{
 | |
| 				ID:            snowflake.GetId(),
 | |
| 				Name:          pfile.Name,
 | |
| 				Path:          pfile.Path,
 | |
| 				ProjectID:     form.ID,
 | |
| 				CreatedUserID: authUser.ID,
 | |
| 			})
 | |
| 		}
 | |
| 		err := projectservice.UpdateProject(ctx, p, cpfs)
 | |
| 		if err != nil {
 | |
| 			tpl.JSONERR(w, err.Error())
 | |
| 			return
 | |
| 		}
 | |
| 		tpl.JSONOK(w, "更新成功")
 | |
| 	} else {
 | |
| 		p := &db.CreateProjectParams{
 | |
| 			ID:            snowflake.GetId(),
 | |
| 			Name:          form.Name,
 | |
| 			StartAt:       form.StartAt,
 | |
| 			EndAt:         form.EndAt,
 | |
| 			CustomerID:    form.CustomerID,
 | |
| 			TotalMoney:    form.TotalMoneyF,
 | |
| 			Description:   form.Description,
 | |
| 			ApplyAt:       form.ApplyAt,
 | |
| 			ApplyUserID:   form.ApplyUserID,
 | |
| 			ManagerID:     form.ManagerID,
 | |
| 			Members:       form.Members,
 | |
| 			Status:        form.Status,
 | |
| 			CreatedUserID: authUser.ID,
 | |
| 		}
 | |
| 		cpfs := []*db.CreateProjectFileParams{}
 | |
| 		for _, pfile := range form.ProjectFiles.ProjectFileItems {
 | |
| 			cpfs = append(cpfs, &db.CreateProjectFileParams{
 | |
| 				ID:            snowflake.GetId(),
 | |
| 				Name:          pfile.Name,
 | |
| 				Path:          pfile.Path,
 | |
| 				ProjectID:     p.ID,
 | |
| 				CreatedUserID: authUser.ID,
 | |
| 			})
 | |
| 		}
 | |
| 		err := projectservice.CreateProject(ctx, p, cpfs)
 | |
| 		if err != nil {
 | |
| 			tpl.JSONERR(w, err.Error())
 | |
| 			return
 | |
| 		}
 | |
| 		tpl.JSONOK(w, "添加成功")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func XmSelect(w http.ResponseWriter, r *http.Request) {
 | |
| 	all, err := db.Engine.AllProjects(r.Context())
 | |
| 	if err != nil {
 | |
| 		tpl.JSONERR(w, err.Error())
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var res []*dto.XmSelectStrDto
 | |
| 	for _, v := range all {
 | |
| 		res = append(res, &dto.XmSelectStrDto{
 | |
| 			Name:  v.Name,
 | |
| 			Value: strconv.FormatInt(v.ID, 10),
 | |
| 		})
 | |
| 	}
 | |
| 	tpl.JSON(w, res)
 | |
| }
 | |
| 
 | |
| func Dashboard(w http.ResponseWriter, r *http.Request) {
 | |
| 	tpl.HTML(w, r, "project/dashboard.tmpl", map[string]any{
 | |
| 		"Projects": projectservice.AllProjects(r.Context()),
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func PostDashboard(w http.ResponseWriter, r *http.Request) {
 | |
| 	ctx := r.Context()
 | |
| 	t := r.PostFormValue("type")
 | |
| 	if t == "project" {
 | |
| 		var projectIncome float64
 | |
| 		var projectExpense float64
 | |
| 		projectID := convertor.ConvertInt[int64](r.PostFormValue("projectID"), 0)
 | |
| 		if projectID == 0 {
 | |
| 			si, _ := db.Engine.SumIncome(ctx)
 | |
| 			projectIncome = convertor.NumericToFloat64(si)
 | |
| 			se, _ := db.Engine.SumExpense(ctx)
 | |
| 			projectExpense = convertor.NumericToFloat64(se)
 | |
| 		} else {
 | |
| 			pi, _ := db.Engine.SumIncomeByProjectID(ctx, projectID)
 | |
| 			projectIncome = convertor.NumericToFloat64(pi)
 | |
| 			pe, _ := db.Engine.SumExpenseByProjectID(ctx, projectID)
 | |
| 			projectExpense = convertor.NumericToFloat64(pe)
 | |
| 		}
 | |
| 
 | |
| 		projectProfit := projectIncome - projectExpense
 | |
| 		var projectProfitRate float64 = 0
 | |
| 		if projectExpense > 0 {
 | |
| 			projectProfitRate = projectProfit / projectExpense
 | |
| 		}
 | |
| 
 | |
| 		res := &view.DashboardProject{
 | |
| 			ProjectIncome:        projectIncome,
 | |
| 			ProjectExpense:       projectExpense,
 | |
| 			ProjectProfit:        projectProfit,
 | |
| 			ProjectProfitRate:    fmt.Sprintf("%0.2f%%", projectProfitRate*100),
 | |
| 			IncomeExpenseEcharts: incomeExpenseEcharts(ctx, projectID),
 | |
| 			IncomeEcharts:        incomeEcharts(ctx, projectID),
 | |
| 			ExpenseEcharts:       expenseEcharts(ctx, projectID),
 | |
| 		}
 | |
| 		tpl.JSON(w, tpl.Response{Success: true, Message: "ok", Data: res})
 | |
| 		return
 | |
| 	} else if t == "budget" {
 | |
| 	}
 | |
| 	tpl.JSONERR(w, "failed to valid type")
 | |
| }
 | |
| 
 | |
| func validForm(r *http.Request) (formDto.ProjectForm, error) {
 | |
| 	// data := &form.ProjectForm{}
 | |
| 	// if err := form.BindForm(r, data); err != nil {
 | |
| 	// 	return data, err
 | |
| 	// }
 | |
| 
 | |
| 	// if err := data.TotalMoneyF.Scan(data.TotalMoney); err != nil {
 | |
| 	// 	return data, errors.New("总金额格式错误")
 | |
| 	// }
 | |
| 
 | |
| 	// if len(data.Members) > 0 {
 | |
| 	// 	membersSplit := strings.SplitSeq(data.Members, ",")
 | |
| 	// 	for v := range membersSplit {
 | |
| 	// 		m := convertor.ConvertInt[int32](v, 0)
 | |
| 	// 		if m == 0 {
 | |
| 	// 			return data, errors.New("项目成员数据错误")
 | |
| 	// 		}
 | |
| 	// 	}
 | |
| 	// }
 | |
| 
 | |
| 	// data.ProjectFiles = &formDto.ProjectFileForm{
 | |
| 	// 	ProjectFileItems: []*formDto.ProjectFileItemForm{},
 | |
| 	// }
 | |
| 	// if len(data.Paths) > 0 {
 | |
| 	// 	fnsSplit := strings.SplitSeq(data.Paths, ",")
 | |
| 	// 	for v := range fnsSplit {
 | |
| 	// 		if len(v) > 0 {
 | |
| 	// 			read := strings.Split(v, "|")
 | |
| 	// 			if len(read) != 2 {
 | |
| 	// 				return data, errors.New("文件路径数据错误")
 | |
| 	// 			}
 | |
| 	// 			pff := &formDto.ProjectFileItemForm{
 | |
| 	// 				Name:        read[0],
 | |
| 	// 				Path:        read[1],
 | |
| 	// 				Combination: v,
 | |
| 	// 			}
 | |
| 	// 			data.ProjectFiles.ProjectFileItems = append(data.ProjectFiles.ProjectFileItems, pff)
 | |
| 	// 		}
 | |
| 	// 	}
 | |
| 	// }
 | |
| 
 | |
| 	// return data, nil
 | |
| 
 | |
| 	var err error
 | |
| 	form := formDto.ProjectForm{}
 | |
| 
 | |
| 	form.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
 | |
| 	form.CustomerID, err = strconv.ParseInt(r.PostFormValue("CustomerID"), 10, 64)
 | |
| 	if err != nil || form.CustomerID == 0 {
 | |
| 		return form, errors.New("客户不能为空")
 | |
| 	}
 | |
| 
 | |
| 	form.Name = r.PostFormValue("Name")
 | |
| 	if len(form.Name) == 0 {
 | |
| 		return form, errors.New("名称不能为空")
 | |
| 	}
 | |
| 	form.StartAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("StartAt"), time.Local)
 | |
| 	if err != nil {
 | |
| 		return form, errors.New("开始时间格式错误")
 | |
| 	}
 | |
| 	form.EndAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("EndAt"), time.Local)
 | |
| 	if err != nil {
 | |
| 		return form, errors.New("结束时间格式错误")
 | |
| 	}
 | |
| 
 | |
| 	if err := form.TotalMoneyF.Scan(r.PostFormValue("TotalMoney")); err != nil {
 | |
| 		return form, errors.New("总金额格式错误")
 | |
| 	}
 | |
| 
 | |
| 	form.Description = r.PostFormValue("Description")
 | |
| 	form.ApplyAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("ApplyAt"), time.Local)
 | |
| 	if err != nil {
 | |
| 		return form, errors.New("申请时间格式错误")
 | |
| 	}
 | |
| 	form.ApplyUserID = convertor.ConvertInt[int32](r.PostFormValue("ApplyUserID"), 0)
 | |
| 	if form.ApplyUserID == 0 {
 | |
| 		return form, errors.New("申请人不能为空")
 | |
| 	}
 | |
| 
 | |
| 	form.ManagerID = convertor.ConvertInt[int32](r.PostFormValue("ManagerID"), 0)
 | |
| 	if form.ManagerID == 0 {
 | |
| 		return form, errors.New("项目经理不能为空")
 | |
| 	}
 | |
| 
 | |
| 	form.Members = r.PostFormValue("Members")
 | |
| 	if len(form.Members) > 0 {
 | |
| 		membersSplit := strings.SplitSeq(form.Members, ",")
 | |
| 		for v := range membersSplit {
 | |
| 			m := convertor.ConvertInt[int32](v, 0)
 | |
| 			if m == 0 {
 | |
| 				return form, errors.New("项目成员数据错误")
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	form.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
 | |
| 
 | |
| 	form.ProjectFiles = &formDto.ProjectFileForm{
 | |
| 		ProjectFileItems: []*formDto.ProjectFileItemForm{},
 | |
| 	}
 | |
| 	fns := r.PostFormValue("Paths")
 | |
| 	if len(fns) > 0 {
 | |
| 		fnsSplit := strings.SplitSeq(fns, ",")
 | |
| 		for v := range fnsSplit {
 | |
| 			if len(v) > 0 {
 | |
| 				read := strings.Split(v, "|")
 | |
| 				if len(read) != 2 {
 | |
| 					return form, errors.New("文件路径数据错误")
 | |
| 				}
 | |
| 				pff := &formDto.ProjectFileItemForm{
 | |
| 					Name:        read[0],
 | |
| 					Path:        read[1],
 | |
| 					Combination: v,
 | |
| 				}
 | |
| 				form.ProjectFiles.ProjectFileItems = append(form.ProjectFiles.ProjectFileItems, pff)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return form, nil
 | |
| }
 | |
| 
 | |
| func incomeExpenseEcharts(ctx context.Context, projectId int64) view.EchartsOption {
 | |
| 	var name []string
 | |
| 	var income []float64
 | |
| 	var expense []float64
 | |
| 
 | |
| 	if projectId == 0 {
 | |
| 		rows, err := db.Engine.StatisticsProjects(ctx)
 | |
| 		if err != nil || len(rows) == 0 {
 | |
| 			return view.EchartsOption{}
 | |
| 		}
 | |
| 
 | |
| 		for _, row := range rows {
 | |
| 			name = append(name, row.Name)
 | |
| 			income = append(income, convertor.NumericToFloat64(row.Income))
 | |
| 			expense = append(expense, convertor.NumericToFloat64(row.Expense))
 | |
| 		}
 | |
| 	} else {
 | |
| 		row, err := db.Engine.StatisticsProjectItem(ctx, projectId)
 | |
| 		if err != nil || row == nil {
 | |
| 			return view.EchartsOption{}
 | |
| 		}
 | |
| 		name = append(name, row.Name)
 | |
| 		income = append(income, convertor.NumericToFloat64(row.Income))
 | |
| 		expense = append(expense, convertor.NumericToFloat64(row.Expense))
 | |
| 	}
 | |
| 
 | |
| 	return view.EchartsOption{
 | |
| 		Title: view.Title{
 | |
| 			Text:     "项目收支情况",
 | |
| 			Left:     "center",
 | |
| 			Top:      2,
 | |
| 			FontSize: 15,
 | |
| 			TextStyle: view.TextStyle{
 | |
| 				Color:      "#666666",
 | |
| 				FontWeight: "normal",
 | |
| 			},
 | |
| 		},
 | |
| 		Color: []string{"#fed46b", "#2194ff"},
 | |
| 		ToolTip: view.ToolTip{
 | |
| 			Trigger: "axis",
 | |
| 			AxisPointer: view.AxisPointer{
 | |
| 				Type: "shadow",
 | |
| 			},
 | |
| 		},
 | |
| 		Grid: view.Grid{
 | |
| 			Left:         "3%",
 | |
| 			Right:        "4%",
 | |
| 			Bottom:       "10%",
 | |
| 			ContainLabel: true,
 | |
| 		},
 | |
| 		Legend: view.Legend{
 | |
| 			Left: "center",
 | |
| 			Top:  "bottom",
 | |
| 			Data: []string{"支出金额", "收入金额"},
 | |
| 		},
 | |
| 		XAxis: []view.XAxis{
 | |
| 			{
 | |
| 				Type: "category",
 | |
| 				Data: name,
 | |
| 				AxisTick: view.AxisTick{
 | |
| 					AlignWithLabel: true,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		YAxis: []view.YAxis{
 | |
| 			{
 | |
| 				Type: "value",
 | |
| 				Name: "单位:元",
 | |
| 			},
 | |
| 		},
 | |
| 		BarMaxWidth: "30",
 | |
| 		Label: view.Label{
 | |
| 			Show:     true,
 | |
| 			Position: "top",
 | |
| 		},
 | |
| 		Series: []view.Series{
 | |
| 			{
 | |
| 				Name: "支出金额",
 | |
| 				Type: "bar",
 | |
| 				Data: expense,
 | |
| 				ItemStyle: view.ItemStyle{
 | |
| 					Normal: view.Normal{
 | |
| 						Color: "#f89588",
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			{
 | |
| 				Name: "收入金额",
 | |
| 				Type: "bar",
 | |
| 				Data: income,
 | |
| 				ItemStyle: view.ItemStyle{
 | |
| 					Normal: view.Normal{
 | |
| 						Color: "#76da91",
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func incomeEcharts(ctx context.Context, projectId int64) view.EchartsOption {
 | |
| 	var name []string
 | |
| 	data := []view.DataItem{}
 | |
| 
 | |
| 	if projectId == 0 {
 | |
| 		rows, err := db.Engine.StatisticsIncome(ctx)
 | |
| 		if err != nil || len(rows) == 0 {
 | |
| 			return view.EchartsOption{}
 | |
| 		}
 | |
| 
 | |
| 		for _, row := range rows {
 | |
| 			name = append(name, row.IncomeTypeName)
 | |
| 			data = append(data, view.DataItem{
 | |
| 				Name:  row.IncomeTypeName,
 | |
| 				Value: convertor.NumericToFloat64(row.TotalAmount),
 | |
| 			})
 | |
| 		}
 | |
| 	} else {
 | |
| 		rows, err := db.Engine.StatisticsIncomeByProjectID(ctx, projectId)
 | |
| 		if err != nil || len(rows) == 0 {
 | |
| 			return view.EchartsOption{}
 | |
| 		}
 | |
| 
 | |
| 		for _, row := range rows {
 | |
| 			name = append(name, row.IncomeTypeName)
 | |
| 			data = append(data, view.DataItem{
 | |
| 				Name:  row.IncomeTypeName,
 | |
| 				Value: convertor.NumericToFloat64(row.TotalAmount),
 | |
| 			})
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return view.EchartsOption{
 | |
| 		Title: view.Title{
 | |
| 			Text:     "收入分布",
 | |
| 			Left:     "center",
 | |
| 			Orient:   "vertical",
 | |
| 			FontSize: 15,
 | |
| 			TextStyle: view.TextStyle{
 | |
| 				Color:      "#666666",
 | |
| 				FontWeight: "normal",
 | |
| 			},
 | |
| 		},
 | |
| 		ToolTip: view.ToolTip{
 | |
| 			Trigger: "item",
 | |
| 		},
 | |
| 		Legend: view.Legend{
 | |
| 			Left: "center",
 | |
| 			Top:  "bottom",
 | |
| 			Data: name,
 | |
| 		},
 | |
| 		Color: []string{"#63b2ee", "#76da91", "#f8cb7f", "#f89588", "#7cd6cf", "#9192ab", "#7898e1", "#efa666", "#eddd86", "#9987ce", "#63b2ee", "#76da91"},
 | |
| 		Series: []view.Series{
 | |
| 			{
 | |
| 				Type:   "pie",
 | |
| 				Radius: "50%",
 | |
| 				Data:   data,
 | |
| 				Label: view.Label{
 | |
| 					Show: true,
 | |
| 					TextStyle: view.TextStyle{
 | |
| 						Color: "#666666",
 | |
| 					},
 | |
| 					Normal: view.LableNormal{
 | |
| 						Formatter: "{c} ({d}%)",
 | |
| 						TextStyle: view.TextStyle{
 | |
| 							Color:      "#666666",
 | |
| 							FontWeight: "normal",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func expenseEcharts(ctx context.Context, projectId int64) view.EchartsOption {
 | |
| 	var name []string
 | |
| 	data := []view.DataItem{}
 | |
| 
 | |
| 	if projectId == 0 {
 | |
| 		rows, err := db.Engine.StatisticsExpense(ctx)
 | |
| 		if err != nil || len(rows) == 0 {
 | |
| 			return view.EchartsOption{}
 | |
| 		}
 | |
| 
 | |
| 		for _, row := range rows {
 | |
| 			name = append(name, row.ExpensesTypeName)
 | |
| 			data = append(data, view.DataItem{
 | |
| 				Name:  row.ExpensesTypeName,
 | |
| 				Value: convertor.NumericToFloat64(row.TotalAmount),
 | |
| 			})
 | |
| 		}
 | |
| 	} else {
 | |
| 		rows, err := db.Engine.StatisticsExpenseByProjectID(ctx, projectId)
 | |
| 		if err != nil || len(rows) == 0 {
 | |
| 			return view.EchartsOption{}
 | |
| 		}
 | |
| 
 | |
| 		for _, row := range rows {
 | |
| 			name = append(name, row.ExpensesTypeName)
 | |
| 			data = append(data, view.DataItem{
 | |
| 				Name:  row.ExpensesTypeName,
 | |
| 				Value: convertor.NumericToFloat64(row.TotalAmount),
 | |
| 			})
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return view.EchartsOption{
 | |
| 		Title: view.Title{
 | |
| 			Text:     "支出分布",
 | |
| 			Left:     "center",
 | |
| 			Orient:   "vertical",
 | |
| 			FontSize: 15,
 | |
| 			TextStyle: view.TextStyle{
 | |
| 				Color:      "#666666",
 | |
| 				FontWeight: "normal",
 | |
| 			},
 | |
| 		},
 | |
| 		ToolTip: view.ToolTip{
 | |
| 			Trigger: "item",
 | |
| 		},
 | |
| 		Legend: view.Legend{
 | |
| 			Left: "center",
 | |
| 			Top:  "bottom",
 | |
| 			Data: name,
 | |
| 		},
 | |
| 		Color: []string{"#63b2ee", "#76da91", "#f8cb7f", "#f89588", "#7cd6cf", "#9192ab", "#7898e1", "#efa666", "#eddd86", "#9987ce", "#63b2ee", "#76da91"},
 | |
| 		Series: []view.Series{
 | |
| 			{
 | |
| 				Type:   "pie",
 | |
| 				Radius: "50%",
 | |
| 				Data:   data,
 | |
| 				Label: view.Label{
 | |
| 					Show: true,
 | |
| 					TextStyle: view.TextStyle{
 | |
| 						Color: "#666666",
 | |
| 					},
 | |
| 					Normal: view.LableNormal{
 | |
| 						Formatter: "{c} ({d}%)",
 | |
| 						TextStyle: view.TextStyle{
 | |
| 							Color:      "#666666",
 | |
| 							FontWeight: "normal",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	// return view.EchartsOption{
 | |
| 	// 	Title: view.Title{
 | |
| 	// 		Text:     "支出分布",
 | |
| 	// 		Left:     "center",
 | |
| 	// 		Top:      2,
 | |
| 	// 		FontSize: 15,
 | |
| 	// 		TextStyle: view.TextStyle{
 | |
| 	// 			Color:      "#666666",
 | |
| 	// 			FontWeight: "normal",
 | |
| 	// 		},
 | |
| 	// 	},
 | |
| 	// 	Color: []string{"#fed46b", "#2194ff"},
 | |
| 	// 	ToolTip: view.ToolTip{
 | |
| 	// 		Trigger: "axis",
 | |
| 	// 		AxisPointer: view.AxisPointer{
 | |
| 	// 			Type: "shadow",
 | |
| 	// 		},
 | |
| 	// 	},
 | |
| 	// 	Grid: view.Grid{
 | |
| 	// 		Left:         "3%",
 | |
| 	// 		Right:        "4%",
 | |
| 	// 		Bottom:       "10%",
 | |
| 	// 		ContainLabel: true,
 | |
| 	// 	},
 | |
| 	// 	XAxis: []view.XAxis{
 | |
| 	// 		{
 | |
| 	// 			Type: "category",
 | |
| 	// 			Data: name,
 | |
| 	// 			AxisTick: view.AxisTick{
 | |
| 	// 				AlignWithLabel: true,
 | |
| 	// 			},
 | |
| 	// 		},
 | |
| 	// 	},
 | |
| 	// 	YAxis: []view.YAxis{
 | |
| 	// 		{
 | |
| 	// 			Type: "value",
 | |
| 	// 			Name: "单位:元",
 | |
| 	// 		},
 | |
| 	// 	},
 | |
| 	// 	BarMaxWidth: "30",
 | |
| 	// 	Label: view.Label{
 | |
| 	// 		Show:     true,
 | |
| 	// 		Position: "top",
 | |
| 	// 	},
 | |
| 	// 	Series: []view.Series{
 | |
| 	// 		{
 | |
| 	// 			Type: "bar",
 | |
| 	// 			Data: expense,
 | |
| 	// 			ItemStyle: view.ItemStyle{
 | |
| 	// 				Normal: view.Normal{
 | |
| 	// 					Color: "#f89588",
 | |
| 	// 				},
 | |
| 	// 			},
 | |
| 	// 		},
 | |
| 	// 	},
 | |
| 	// }
 | |
| }
 |