合并分支

This commit is contained in:
2023-08-04 17:11:10 +08:00
parent 12ec8d26bf
commit 020e76b901
100 changed files with 12692 additions and 2574 deletions

View File

@@ -3,8 +3,12 @@ package controller
import (
"electricity_bill_calc/exceptions"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"net/http"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
func _retreiveSession(c *fiber.Ctx) (*model.Session, error) {
@@ -18,3 +22,26 @@ func _retreiveSession(c *fiber.Ctx) (*model.Session, error) {
}
return userSession, nil
}
// 检查当前用户是否拥有指定园区,在判断完成之后直接产生响应
func checkParkBelongs(parkId string, logger *zap.Logger, c *fiber.Ctx, result *response.Result) (bool, error) {
session := c.Locals("session")
if session == nil {
logger.Error("用户会话不存在。")
return false, result.Unauthorized("用户会话不存在。")
}
userSession, ok := session.(*model.Session)
if !ok {
return false, result.Unauthorized("用户会话格式不正确,需要重新登录")
}
ok, err := repository.ParkRepository.IsParkBelongs(parkId, userSession.Uid)
switch {
case err != nil:
logger.Error("无法判断园区是否隶属于当前用户。", zap.String("park id", parkId), zap.String("user id", userSession.Uid), zap.Error(err))
return false, result.Error(http.StatusInternalServerError, err.Error())
case err == nil && !ok:
logger.Error("用户试图访问不属于自己的园区。", zap.String("park id", parkId), zap.String("user id", userSession.Uid))
return false, result.Forbidden("您无权访问该园区。")
}
return true, nil
}

View File

@@ -1,93 +1,97 @@
package controller
import (
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/types"
"net/http"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"github.com/shopspring/decimal"
"go.uber.org/zap"
)
func InitializeChargesController(app *fiber.App) {
app.Get("/charges", security.OPSAuthorize, listAllCharges)
app.Post("/charge", security.OPSAuthorize, recordNewCharge)
app.Put("/charge/:uid/:seq", security.OPSAuthorize, modifyChargeState)
var chargeLog = logger.Named("Handler", "Charge")
func InitializeChargeHandlers(router *fiber.App) {
router.Get("/charge", searchCharges)
router.Post("/charge", createNewUserChargeRecord)
router.Put("/charge/:uid/:seq", modifyUserChargeState)
}
func listAllCharges(c *fiber.Ctx) error {
// 检索用户的充值记录列表
func searchCharges(c *fiber.Ctx) error {
chargeLog.Info("检索用户的充值记录列表。")
result := response.NewResult(c)
requestPage, err := strconv.Atoi(c.Query("page", "1"))
keyword := c.Query("keyword", "")
page := c.QueryInt("page", 1)
beginTime := types.ParseDateWithDefault(c.Query("begin"), types.NewEmptyDate())
endTime := types.ParseDateWithDefault(c.Query("end"), types.MaxDate())
charges, total, err := repository.ChargeRepository.FindCharges(uint(page), &beginTime, &endTime, &keyword)
if err != nil {
return result.NotAccept("查询参数[page]格式不正确。")
chargeLog.Error("检索用户的充值记录列表失败。", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
requestKeyword := c.Query("keyword", "")
requestBeginDate := c.Query("begin", "")
requestEndDate := c.Query("end", "")
charges, total, err := service.ChargeService.ListPagedChargeRecord(requestKeyword, requestBeginDate, requestEndDate, requestPage)
if err != nil {
return result.NotFound(err.Error())
}
return result.Json(
http.StatusOK, "已获取到符合条件的计费记录。",
response.NewPagedResponse(requestPage, total).ToMap(),
return result.Success(
"已经获取到符合条件的计费记录。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"records": charges},
)
}
type _NewChargeFormData struct {
UserId string `json:"userId" form:"userId"`
Fee decimal.NullDecimal `json:"fee" form:"fee"`
Discount decimal.NullDecimal `json:"discount" form:"discount"`
Amount decimal.NullDecimal `json:"amount" form:"amount"`
ChargeTo model.Date `json:"chargeTo" form:"chargeTo"`
}
func recordNewCharge(c *fiber.Ctx) error {
// 创建一条新的用户充值记录
func createNewUserChargeRecord(c *fiber.Ctx) error {
chargeLog.Info("创建一条新的用户充值记录。")
result := response.NewResult(c)
formData := new(_NewChargeFormData)
if err := c.BodyParser(formData); err != nil {
return result.UnableToParse("无法解析提交的数据。")
createionForm := new(model.ChargeRecordCreationForm)
if err := c.BodyParser(createionForm); err != nil {
chargeLog.Error("无法解析创建充值记录的请求数据。", zap.Error(err))
return result.Error(http.StatusBadRequest, err.Error())
}
currentTime := time.Now()
newRecord := &model.UserCharge{
UserId: formData.UserId,
Fee: formData.Fee,
Discount: formData.Discount,
Amount: formData.Amount,
Settled: true,
SettledAt: &currentTime,
ChargeTo: formData.ChargeTo,
}
err := service.ChargeService.CreateChargeRecord(newRecord, true)
fee, _ := createionForm.Fee.Decimal.Float64()
discount, _ := createionForm.Discount.Decimal.Float64()
amount, _ := createionForm.Amount.Decimal.Float64()
ok, err := service.ChargeService.RecordUserCharge(
createionForm.UserId,
&fee,
&discount,
&amount,
createionForm.ChargeTo,
true,
)
if err != nil {
chargeLog.Error("创建用户充值记录失败。", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Created("指定用户的服务已延期。")
if !ok {
chargeLog.Error("创建用户充值记录失败。")
return result.NotAccept("创建用户充值记录失败。")
} else {
return result.Success("创建用户充值记录成功, 指定用户的服务已延期。")
}
}
type _StateChangeFormData struct {
Cancelled bool `json:"cancelled"`
}
func modifyChargeState(c *fiber.Ctx) error {
// 改变用户充值记录的状态
func modifyUserChargeState(c *fiber.Ctx) error {
chargeLog.Info("改变用户充值记录的状态。")
result := response.NewResult(c)
formData := new(_StateChangeFormData)
if err := c.BodyParser(formData); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
requestUserID := c.Params("uid")
requestChargeSeq, err := strconv.Atoi(c.Params("seq", "-1"))
if err != nil || requestChargeSeq == -1 {
return result.Error(http.StatusNotAcceptable, "参数[记录流水号]解析错误。")
}
err = service.ChargeService.CancelCharge(int64(requestChargeSeq), requestUserID)
uid := c.Params("uid")
seq, err := c.ParamsInt("seq")
if err != nil {
chargeLog.Error("无法解析请求参数。", zap.Error(err))
return result.Error(http.StatusBadRequest, err.Error())
}
ok, err := service.ChargeService.CancelUserCharge(uid, int64(seq))
if err != nil {
chargeLog.Error("取消用户充值记录失败。", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("指定用户服务延期记录状态已经更新。")
if !ok {
chargeLog.Error("取消用户充值记录失败。")
return result.NotAccept("取消用户充值记录失败。")
} else {
return result.Success("取消用户充值记录成功。")
}
}

227
controller/invoice.go Normal file
View File

@@ -0,0 +1,227 @@
package controller
import (
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/tools"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
"go.uber.org/zap"
)
var invoiceLog = logger.Named("Controller", "Invoice")
func InitializeInvoiceHandler(router *fiber.App) {
router.Get("/invoice", security.MustAuthenticated, listInvoices)
router.Post("/invoice", security.EnterpriseAuthorize, createNewInvoiceRecord)
router.Post("/invoice/precalculate", security.EnterpriseAuthorize, testCalculateInvoice)
router.Get("/invoice/:code", security.EnterpriseAuthorize, getInvoiceDetail)
router.Delete("/invoice/:code", security.EnterpriseAuthorize, deleteInvoiceRecord)
router.Get("/uninvoiced/tenemennt/:tid/report", security.EnterpriseAuthorize, getUninvoicedTenementReports)
}
// 列出指定园区中的符合条件的发票记录
func listInvoices(c *fiber.Ctx) error {
invoiceLog.Info("列出指定园区中的符合条件的发票记录")
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
invoiceLog.Error("列出指定园区中的符合条件的发票记录失败,不能获取到有效的用户会话。", zap.Error(err))
return result.Unauthorized("未能获取到有效的用户会话。")
}
park := tools.EmptyToNil(c.Query("park"))
if session.Type == model.USER_TYPE_ENT && park != nil && len(*park) > 0 {
pass, err := checkParkBelongs(*park, invoiceLog, c, &result)
if err != nil || !pass {
return err
}
}
startDate, err := types.ParseDatep(c.Query("start_date"))
if err != nil {
invoiceLog.Error("列出指定园区中的符合条件的发票记录失败,开始日期参数解析错误。", zap.Error(err))
return result.BadRequest("开始日期参数解析错误。")
}
endDate, err := types.ParseDatep(c.Query("end_date"))
if err != nil {
invoiceLog.Error("列出指定园区中的符合条件的发票记录失败,结束日期参数解析错误。", zap.Error(err))
return result.BadRequest("结束日期参数解析错误。")
}
keyword := tools.EmptyToNil(c.Query("keyword"))
page := c.QueryInt("page", 1)
invoices, total, err := repository.InvoiceRepository.ListInvoice(park, startDate, endDate, keyword, uint(page))
if err != nil {
invoiceLog.Error("列出指定园区中的符合条件的发票记录失败,检索符合条件的发票记录出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "检索符合条件的发票记录出现错误。")
}
invoiceResponse := make([]*vo.InvoiceResponse, 0)
copier.Copy(&invoiceResponse, &invoices)
return result.Success(
"已经获取到符合条件的发票列表。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{
"invoices": invoiceResponse,
},
)
}
// 获取指定发票的详细信息
func getInvoiceDetail(c *fiber.Ctx) error {
result := response.NewResult(c)
invoiceNo := tools.EmptyToNil(c.Params("code"))
invoiceLog.Info("获取指定发票的详细信息", zap.Stringp("InvoiceNo", invoiceNo))
if invoiceNo == nil {
invoiceLog.Error("获取指定发票的详细信息失败,未指定发票编号。")
return result.BadRequest("未指定发票编号。")
}
session, err := _retreiveSession(c)
if err != nil {
invoiceLog.Error("获取指定发票的详细信息失败,不能获取到有效的用户会话。", zap.Error(err))
return result.Unauthorized("未能获取到有效的用户会话。")
}
pass, err := repository.InvoiceRepository.IsBelongsTo(*invoiceNo, session.Uid)
if err != nil {
invoiceLog.Error("获取指定发票的详细信息失败,检查发票所属权时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "检查发票所属权时出现错误。")
}
if !pass {
invoiceLog.Error("获取指定发票的详细信息失败,发票不属于当前用户。")
return result.Forbidden("不能访问不属于自己的发票。")
}
invoice, err := repository.InvoiceRepository.GetInvoiceDetail(*invoiceNo)
if err != nil {
invoiceLog.Error("获取指定发票的详细信息失败,检索发票信息时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "检索发票信息时出现错误。")
}
if invoice == nil {
invoiceLog.Error("获取指定发票的详细信息失败,指定发票不存在。")
return result.NotFound("指定发票不存在。")
}
var invoiceResponse vo.ExtendedInvoiceResponse
copier.Copy(&invoiceResponse, &invoice)
return result.Success(
"已经获取到指定发票的详细信息。",
fiber.Map{
"invoice": invoiceResponse,
},
)
}
// 获取指定商户下所有尚未开票的核算项目
func getUninvoicedTenementReports(c *fiber.Ctx) error {
result := response.NewResult(c)
tenement := tools.EmptyToNil(c.Params("tid"))
invoiceLog.Info("获取指定商户下所有尚未开票的核算项目", zap.Stringp("Tenement", tenement))
if tenement == nil {
invoiceLog.Error("获取指定商户下所有尚未开票的核算项目失败,未指定商户。")
return result.BadRequest("未指定商户。")
}
session, err := _retreiveSession(c)
if err != nil {
invoiceLog.Error("获取指定商户下所有尚未开票的核算项目失败,不能获取到有效的用户会话。", zap.Error(err))
return result.Unauthorized("未能获取到有效的用户会话。")
}
pass, err := repository.TenementRepository.IsTenementBelongs(*tenement, session.Uid)
if err != nil {
invoiceLog.Error("获取指定商户下所有尚未开票的核算项目失败,检查商户所属权时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "检查商户所属权时出现错误。")
}
if !pass {
invoiceLog.Error("获取指定商户下所有尚未开票的核算项目失败,商户不属于当前用户。")
return result.Forbidden("不能访问不属于自己的商户。")
}
reports, err := repository.InvoiceRepository.ListUninvoicedTenementCharges(*tenement)
if err != nil {
invoiceLog.Error("获取指定商户下所有尚未开票的核算项目失败,检索核算项目时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "检索核算项目时出现错误。")
}
return result.Success(
"已经获取到指定商户下所有尚未开票的核算项目。",
fiber.Map{
"records": reports,
},
)
}
// 试计算指定发票的票面信息
func testCalculateInvoice(c *fiber.Ctx) error {
result := response.NewResult(c)
var form vo.InvoiceCreationForm
if err := c.BodyParser(&form); err != nil {
invoiceLog.Error("试计算指定发票的票面信息失败,请求表单数据解析错误。", zap.Error(err))
return result.BadRequest("请求表单数据解析错误。")
}
invoiceLog.Info("试计算指定发票的票面信息", zap.String("Park", form.Park), zap.String("Tenement", form.Tenement))
if pass, err := checkParkBelongs(form.Park, invoiceLog, c, &result); err != nil || !pass {
return err
}
total, cargos, err := service.InvoiceService.TestCalculateInvoice(form.Park, form.Tenement, form.TaxMethod, form.TaxRate, form.Covers)
if err != nil {
invoiceLog.Error("试计算指定发票的票面信息失败,试计算发票时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "试计算发票时出现错误。")
}
return result.Success(
"已经计算出指定发票的票面信息。",
fiber.Map{
"total": total,
"cargos": cargos,
},
)
}
// 创建一个新的发票记录
func createNewInvoiceRecord(c *fiber.Ctx) error {
result := response.NewResult(c)
var form vo.ExtendedInvoiceCreationForm
if err := c.BodyParser(&form); err != nil {
invoiceLog.Error("创建一个新的发票记录失败,请求表单数据解析错误。", zap.Error(err))
return result.BadRequest("请求表单数据解析错误。")
}
invoiceLog.Info("创建一个新的发票记录", zap.String("Park", form.Park), zap.String("Tenement", form.Tenement))
if pass, err := checkParkBelongs(form.Park, invoiceLog, c, &result); err != nil || !pass {
return err
}
err := service.InvoiceService.SaveInvoice(form.Park, form.Tenement, form.InvoiceNo, form.InvoiceType, form.TaxMethod, form.TaxRate, form.Covers)
if err != nil {
invoiceLog.Error("创建一个新的发票记录失败,保存发票时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "保存发票时出现错误。")
}
return result.Created("已经创建了一个新的发票记录。")
}
// 删除指定的发票记录
func deleteInvoiceRecord(c *fiber.Ctx) error {
result := response.NewResult(c)
invoiceNo := tools.EmptyToNil(c.Params("code"))
invoiceLog.Info("删除指定的发票记录", zap.Stringp("InvoiceNo", invoiceNo))
if invoiceNo == nil {
invoiceLog.Error("删除指定的发票记录失败,未指定发票编号。")
return result.BadRequest("未指定发票编号。")
}
session, err := _retreiveSession(c)
if err != nil {
invoiceLog.Error("删除指定的发票记录失败,不能获取到有效的用户会话。", zap.Error(err))
return result.Unauthorized("未能获取到有效的用户会话。")
}
pass, err := repository.InvoiceRepository.IsBelongsTo(*invoiceNo, session.Uid)
if err != nil {
invoiceLog.Error("删除指定的发票记录失败,检查发票所属权时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "检查发票所属权时出现错误。")
}
if !pass {
invoiceLog.Error("删除指定的发票记录失败,发票不属于当前用户。")
return result.Forbidden("不能删除不属于自己的发票。")
}
err = service.InvoiceService.DeleteInvoice(*invoiceNo)
if err != nil {
invoiceLog.Error("删除指定的发票记录失败,删除发票时出现错误。", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "删除发票时出现错误。")
}
return result.Success("已经删除了指定的发票记录。")
}

502
controller/meter.go Normal file
View File

@@ -0,0 +1,502 @@
package controller
import (
"electricity_bill_calc/excel"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/tools"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"fmt"
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
"github.com/samber/lo"
"go.uber.org/zap"
)
var meterLog = logger.Named("Handler", "Meter")
func InitializeMeterHandlers(router *fiber.App) {
router.Get("/meter/choice", security.EnterpriseAuthorize, listUnboundMeters)
router.Get("/meter/choice/tenement", security.EnterpriseAuthorize, listUnboundTenementMeters)
router.Get("/meter/:pid", security.EnterpriseAuthorize, searchMetersWithinPark)
router.Post("/meter/:pid", security.EnterpriseAuthorize, createNewMeterManually)
router.Get("/meter/:pid/template", security.EnterpriseAuthorize, downloadMeterArchiveTemplate)
router.Post("/meter/:pid/batch", security.EnterpriseAuthorize, uploadMeterArchive)
router.Get("/meter/:pid/pooled", security.EnterpriseAuthorize, listPooledMeters)
router.Get("/meter/:pid/:code", security.EnterpriseAuthorize, retrieveSpecificMeterDetail)
router.Put("/meter/:pid/:code", security.EnterpriseAuthorize, updateMeterManually)
router.Patch("/meter/:pid/:code", security.EnterpriseAuthorize, replaceMeter)
router.Get("/meter/:pid/:code/binding", security.EnterpriseAuthorize, listAssociatedMeters)
router.Post("/meter/:pid/:code/binding", security.EnterpriseAuthorize, bindAssociatedMeters)
router.Delete("/meter/:pid/:code/binding/:slave", security.EnterpriseAuthorize, unbindAssociatedMeters)
router.Get("/reading/:pid", security.EnterpriseAuthorize, queryMeterReadings)
router.Put("/reading/:pid/:code/:reading", security.EnterpriseAuthorize, updateMeterReading)
router.Get("/reading/:pid/template", security.EnterpriseAuthorize, downloadMeterReadingsTemplate)
router.Post("/reading/:pid/batch", security.EnterpriseAuthorize, uploadMeterReadings)
router.Post("/reading/:pid/:code", security.EnterpriseAuthorize, recordMeterReading)
}
// 查询指定园区下的表计信息
func searchMetersWithinPark(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterLog.Info("查询指定园区下的表计信息", zap.String("park id", parkId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
keyword := c.Query("keyword")
page := c.QueryInt("page", 1)
meters, total, err := repository.MeterRepository.MetersIn(parkId, uint(page), &keyword)
if err != nil {
meterLog.Error("无法查询指定园区下的表计信息,无法获取表计列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success(
"已经取得符合条件的0.4kV表计列表。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"meters": meters},
)
}
// 查询指定园区中指定表计的详细信息
func retrieveSpecificMeterDetail(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterId := c.Params("code")
meterLog.Info("查询指定园区中指定表计的详细信息", zap.String("park id", parkId), zap.String("meter id", meterId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
meter, err := repository.MeterRepository.FetchMeterDetail(parkId, meterId)
if err != nil {
meterLog.Error("无法查询指定园区中指定表计的详细信息,无法获取表计信息", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if meter == nil {
meterLog.Warn("无法查询指定园区中指定表计的详细信息,表计不存在")
return result.NotFound("指定的表计不存在。")
}
return result.Success("指定表计信息已经找到。", fiber.Map{"meter": meter})
}
// 手动添加一条0.4kV表计记录
func createNewMeterManually(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterLog.Info("手动添加一条0.4kV表计记录", zap.String("park id", parkId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
var creationForm vo.MeterCreationForm
if err := c.BodyParser(&creationForm); err != nil {
meterLog.Error("无法手动添加一条0.4kV表计记录,无法解析表计创建表单", zap.Error(err))
return result.NotAccept(err.Error())
}
if err := service.MeterService.CreateMeterRecord(parkId, &creationForm); err != nil {
meterLog.Error("无法手动添加一条0.4kV表计记录,无法创建表计记录", zap.Error(err))
return result.NotAccept(err.Error())
}
return result.Created("新0.4kV表计已经添加完成。")
}
// 手动更新一条新的0.4kV表计记录
func updateMeterManually(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterId := c.Params("code")
meterLog.Info("手动更新一条新的0.4kV表计记录", zap.String("park id", parkId), zap.String("meter id", meterId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
var updateForm vo.MeterModificationForm
if err := c.BodyParser(&updateForm); err != nil {
meterLog.Error("无法手动更新一条新的0.4kV表计记录,无法解析表计更新表单", zap.Error(err))
return result.NotAccept(err.Error())
}
if err := service.MeterService.UpdateMeterRecord(parkId, meterId, &updateForm); err != nil {
meterLog.Error("无法手动更新一条新的0.4kV表计记录,无法更新表计记录", zap.Error(err))
return result.NotAccept(err.Error())
}
return result.Updated("0.4kV表计已经更新完成。")
}
// 下载指定的园区表计登记模板
func downloadMeterArchiveTemplate(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterLog.Info("下载指定的园区表计登记模板", zap.String("park id", parkId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
parkDetail, err := repository.ParkRepository.RetrieveParkDetail(parkId)
if err != nil {
meterLog.Error("无法下载指定的园区表计登记模板,无法获取园区信息", zap.Error(err))
return result.NotFound(err.Error())
}
buildings, err := repository.ParkRepository.RetrieveParkBuildings(parkId)
if err != nil {
meterLog.Error("无法下载指定的园区表计登记模板,无法获取园区建筑列表", zap.Error(err))
return result.NotFound(fmt.Sprintf("无法获取园区建筑列表,%s", err.Error()))
}
if err != nil {
meterLog.Error("无法下载指定的园区表计登记模板,无法生成表计登记模板", zap.Error(err))
return result.NotFound(fmt.Sprintf("无法生成表计登记模板,%s", err.Error()))
}
templateGenerator := excel.NewMeterArchiveExcelTemplateGenerator()
defer templateGenerator.Close()
err = templateGenerator.WriteTemplateData(buildings)
if err != nil {
meterLog.Error("无法下载指定的园区表计登记模板,无法生成表计登记模板", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, fmt.Sprintf("无法生成表计登记模板,%s", err.Error()))
}
c.Status(fiber.StatusOK)
c.Set(fiber.HeaderContentType, fiber.MIMEOctetStream)
c.Set("Content-Transfer-Encoding", "binary")
c.Set(fiber.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s-表计登记模板.xlsx", parkDetail.Name))
templateGenerator.WriteTo(c.Response().BodyWriter())
return nil
}
// 从Excel文件中导入表计档案
func uploadMeterArchive(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
uploadFile, err := c.FormFile("data")
if err != nil {
meterLog.Error("无法从Excel文件中导入表计档案无法获取上传的文件", zap.Error(err))
return result.NotAccept(fmt.Sprintf("没有接收到上传的文件,%s", err.Error()))
}
errs, err := service.MeterService.BatchImportMeters(parkId, uploadFile)
if err != nil {
meterLog.Error("无法从Excel文件中导入表计档案无法导入表计档案", zap.Error(err))
return result.Json(fiber.StatusNotAcceptable, "上传的表计档案存在错误。", fiber.Map{"errors": errs})
}
return result.Success("表计档案已经导入完成。", fiber.Map{"errors": errs})
}
// 更换系统中的表计
func replaceMeter(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterId := c.Params("code")
meterLog.Info("更换系统中的表计", zap.String("park id", parkId), zap.String("meter id", meterId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
var replacementForm vo.MeterReplacingForm
if err := c.BodyParser(&replacementForm); err != nil {
meterLog.Error("无法更换系统中的表计,无法解析表计更换表单", zap.Error(err))
return result.NotAccept(err.Error())
}
return nil
}
// 列出指定公摊表计下的所有关联表计
func listAssociatedMeters(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
meterId := c.Params("code")
meterLog.Info("列出指定公摊表计下的所有关联表计", zap.String("park id", parkId), zap.String("meter id", meterId))
meters, err := service.MeterService.ListPooledMeterRelations(parkId, meterId)
if err != nil {
meterLog.Error("无法列出指定公摊表计下的所有关联表计,无法获取关联表计列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success("已经取得指定公摊表计下的所有关联表计列表。", fiber.Map{"meters": meters})
}
// 向指定表计绑定关联表计
func bindAssociatedMeters(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
meterId := c.Params("code")
meterLog.Info("向指定表计绑定关联表计", zap.String("park id", parkId), zap.String("meter id", meterId))
var meters = make([]string, 0)
if err := c.BodyParser(&meters); err != nil {
meterLog.Error("无法向指定表计绑定关联表计,无法解析关联表计列表", zap.Error(err))
return result.NotAccept(err.Error())
}
ok, err := service.MeterService.BindMeter(parkId, meterId, meters)
if err != nil {
meterLog.Error("无法向指定表计绑定关联表计,无法绑定关联表计", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !ok {
meterLog.Warn("无法向指定表计绑定关联表计,表计关联失败。")
return result.NotAccept("表计关联失败。")
}
return result.Created("已经向指定表计绑定关联表计。")
}
// 解除指定园区下两个表计之间的关联关系
func unbindAssociatedMeters(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
masterMeter := c.Params("code")
slaveMeter := c.Params("slave")
if len(masterMeter) == 0 || len(slaveMeter) == 0 {
meterLog.Warn("无法解除指定园区下两个表计之间的关联关系,表计编号为空。")
return result.NotAccept("存在未给定要操作的表计编号。")
}
ok, err := service.MeterService.UnbindMeter(parkId, masterMeter, []string{slaveMeter})
if err != nil {
meterLog.Error("无法解除指定园区下两个表计之间的关联关系,无法解除关联关系", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !ok {
meterLog.Warn("无法解除指定园区下两个表计之间的关联关系,表计关联解除失败。")
return result.NotAccept("表计关联解除失败。")
}
return result.Created("已经解除指定园区下两个表计之间的关联关系。")
}
// 分页列出园区中的公摊表计
func listPooledMeters(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
page := c.QueryInt("page", 1)
keyword := c.Query("keyword")
meters, total, err := service.MeterService.SearchPooledMetersDetail(parkId, uint(page), &keyword)
if err != nil {
meterLog.Error("无法分页列出园区中的公摊表计,无法获取公摊表计列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success(
"已经取得符合条件的公摊表计列表。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"meters": meters},
)
}
// 列出指定园区中尚未绑定公摊表计的表计
func listUnboundMeters(c *fiber.Ctx) error {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
meterLog.Error("无法列出指定园区中尚未绑定公摊表计的表计,无法获取当前用户会话", zap.Error(err))
return result.Unauthorized(err.Error())
}
parkId := tools.EmptyToNil(c.Query("park"))
if pass, err := checkParkBelongs(*parkId, meterLog, c, &result); !pass {
return err
}
keyword := c.Query("keyword")
limit := uint(c.QueryInt("limit", 6))
meters, err := repository.MeterRepository.ListUnboundMeters(session.Uid, parkId, &keyword, &limit)
if err != nil {
meterLog.Error("无法列出指定园区中尚未绑定公摊表计的表计,无法获取表计列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
var simplifiedMeters = make([]*vo.SimplifiedMeterQueryResponse, 0)
copier.Copy(&simplifiedMeters, &meters)
return result.Success("已经取得符合条件的表计列表。", fiber.Map{"meters": simplifiedMeters})
}
// 列出指定园区中尚未绑定商户的表计
func listUnboundTenementMeters(c *fiber.Ctx) error {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
meterLog.Error("无法列出指定园区中尚未绑定商户的表计,无法获取当前用户会话", zap.Error(err))
return result.Unauthorized(err.Error())
}
parkId := c.Query("park")
if len(parkId) == 0 {
meterLog.Error("无法列出指定园区中尚未绑定商户的表计未指定要访问的园区ID")
return result.NotAccept("未指定要访问的园区。")
}
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
keyword := c.Query("keyword")
limit := uint(c.QueryInt("limit", 6))
meters, err := repository.MeterRepository.ListUnboundTenementMeters(session.Uid, &parkId, &keyword, &limit)
if err != nil {
meterLog.Error("无法列出指定园区中尚未绑定商户的表计,无法获取表计列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
var simplifiedMeters = make([]*vo.SimplifiedMeterQueryResponse, 0)
copier.Copy(&simplifiedMeters, &meters)
return result.Success("已经取得符合条件的表计列表。", fiber.Map{"meters": simplifiedMeters})
}
// 查询指定园区中的表计读数
func queryMeterReadings(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
keyword := tools.EmptyToNil(c.Query("keyword"))
page := c.QueryInt("page", 1)
building := tools.EmptyToNil(c.Query("building"))
start := c.Query("start_date")
var startDate *types.Date = nil
if len(start) > 0 {
if parsedDate, err := types.ParseDate(start); err != nil {
meterLog.Error("查询指定园区中的表计读数,无法解析开始日期", zap.Error(err))
} else {
startDate = &parsedDate
}
}
end := c.Query("end_date")
var endDate *types.Date = nil
if len(end) > 0 {
if parsedDate, err := types.ParseDate(end); err != nil {
meterLog.Error("查询指定园区中的表计读数,无法解析结束日期", zap.Error(err))
} else {
endDate = &parsedDate
}
}
readings, total, err := service.MeterService.SearchMeterReadings(parkId, building, startDate, endDate, uint(page), keyword)
if err != nil {
meterLog.Error("查询指定园区中的表计读数,无法获取表计读数列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
convertedReadings := lo.Map(readings, func(element *model.DetailedMeterReading, _ int) vo.MeterReadingDetailResponse {
return vo.FromDetailedMeterReading(*element)
})
return result.Success(
"指定园区的表计读数已经列出。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"records": convertedReadings},
)
}
// 记录一条新的表计抄表记录
func recordMeterReading(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
meterCode := c.Params("code")
var readingForm vo.MeterReadingForm
if err := c.BodyParser(&readingForm); err != nil {
meterLog.Error("记录一条新的表计抄表记录,无法解析表计抄表表单", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法解析表计抄表表单,%s", err.Error()))
}
if !readingForm.Validate() {
meterLog.Warn("记录一条新的表计抄表记录,表计读数不能正常配平,尖、峰、谷电量和超过总电量。")
return result.NotAccept("表计读数不能正常配平,尖、峰、谷电量和超过总电量。")
}
err := service.MeterService.RecordReading(parkId, meterCode, &readingForm)
if err != nil {
meterLog.Error("记录一条新的表计抄表记录,无法记录表计抄表记录", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Created("表计抄表记录已经记录完成。")
}
// 更新指定园区中指定表计的抄表记录
func updateMeterReading(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
meterCode := c.Params("code")
readingAtMicro, err := c.ParamsInt("reading")
if err != nil {
meterLog.Error("更新一条新的表计抄表记录,无法解析抄表时间", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法解析抄表时间,%s", err.Error()))
}
readingAt := types.FromUnixMicro(int64(readingAtMicro))
var readingForm vo.MeterReadingForm
if err := c.BodyParser(&readingForm); err != nil {
meterLog.Error("更新一条新的表计抄表记录,无法解析表计抄表表单", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法解析表计抄表表单,%s", err.Error()))
}
ok, err := repository.MeterRepository.UpdateMeterReading(parkId, meterCode, readingAt, &readingForm)
if err != nil {
meterLog.Error("更新一条新的表计抄表记录,无法更新表计抄表记录", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !ok {
meterLog.Warn("更新一条新的表计抄表记录,表计抄表更新失败。")
return result.NotAccept("表计抄表记录未能成功更新,可能指定抄表记录不存在。")
}
return result.Success("表计抄表记录已经更新完成。")
}
// 下载指定园区的表计抄表模板
func downloadMeterReadingsTemplate(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterLog.Info("下载指定的园区表计抄表模板", zap.String("park id", parkId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
parkDetail, err := repository.ParkRepository.RetrieveParkDetail(parkId)
if err != nil {
meterLog.Error("无法下载指定的园区表计登记模板,无法获取园区信息", zap.Error(err))
return result.NotFound(err.Error())
}
meterDocs, err := repository.MeterRepository.ListMeterDocForTemplate(parkId)
if err != nil {
meterLog.Error("无法下载指定的园区表计抄表模板,无法获取表计档案列表", zap.Error(err))
return result.NotFound(fmt.Sprintf("无法获取表计档案列表,%s", err.Error()))
}
if err != nil {
meterLog.Error("无法下载指定的园区表计登记模板,无法生成表计登记模板", zap.Error(err))
return result.NotFound(fmt.Sprintf("无法生成表计登记模板,%s", err.Error()))
}
templateGenerator := excel.NewMeterReadingsExcelTemplateGenerator()
defer templateGenerator.Close()
err = templateGenerator.WriteTemplateData(meterDocs)
if err != nil {
meterLog.Error("无法下载指定的园区表计抄表模板,无法生成表计抄表模板", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, fmt.Sprintf("无法生成表计抄表模板,%s", err.Error()))
}
c.Status(fiber.StatusOK)
c.Set(fiber.HeaderContentType, fiber.MIMEOctetStream)
c.Set("Content-Transfer-Encoding", "binary")
c.Set(fiber.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s-表计抄表模板.xlsx", parkDetail.Name))
templateGenerator.WriteTo(c.Response().BodyWriter())
return nil
}
// 处理上传的抄表记录文件
func uploadMeterReadings(c *fiber.Ctx) error {
parkId := c.Params("pid")
meterLog.Info("从Excel文件中导入抄表档案", zap.String("park id", parkId))
result := response.NewResult(c)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
uploadFile, err := c.FormFile("data")
if err != nil {
meterLog.Error("无法从Excel文件中导入抄表档案无法获取上传的文件", zap.Error(err))
return result.NotAccept(fmt.Sprintf("没有接收到上传的文件,%s", err.Error()))
}
errs, err := service.MeterService.BatchImportReadings(parkId, uploadFile)
if err != nil {
meterLog.Error("无法从Excel文件中导入抄表档案无法导入抄表档案", zap.Error(err))
return result.Json(fiber.StatusNotAcceptable, "上传的抄表档案存在错误。", fiber.Map{"errors": errs})
}
return result.Success("表计档案已经导入完成。", fiber.Map{"errors": errs})
}

View File

@@ -1,185 +1,331 @@
package controller
import (
"electricity_bill_calc/model"
"electricity_bill_calc/logger"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/tools"
"electricity_bill_calc/vo"
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"github.com/jinzhu/copier"
"github.com/shopspring/decimal"
"go.uber.org/zap"
)
func InitializeParkController(router *fiber.App) {
router.Get("/parks", security.EnterpriseAuthorize, listAllParksUnderSessionUser)
router.Get("/parks/:uid", security.MustAuthenticated, listAllParksUnderSpecificUser)
router.Post("/park", security.EnterpriseAuthorize, createNewPark)
router.Put("/park/:pid", security.EnterpriseAuthorize, modifyPark)
var parkLog = logger.Named("Handler", "Park")
func InitializeParkHandlers(router *fiber.App) {
router.Get("/park", security.EnterpriseAuthorize, listParksBelongsToCurrentUser)
router.Post("/park", security.EnterpriseAuthorize, createPark)
router.Get("/park/belongs/:uid", security.OPSAuthorize, listParksBelongsTo)
router.Get("/park/:pid", security.EnterpriseAuthorize, fetchParkDetail)
router.Put("/park/:pid/enabled", security.EnterpriseAuthorize, changeParkEnableState)
router.Put("/park/:pid", security.EnterpriseAuthorize, modifySpecificPark)
router.Delete("/park/:pid", security.EnterpriseAuthorize, deleteSpecificPark)
router.Put("/park/:pid/enabled", security.EnterpriseAuthorize, modifyParkEnabling)
router.Get("/park/:pid/building", security.EnterpriseAuthorize, listBuildingsBelongsToPark)
router.Post("/park/:pid/building", security.EnterpriseAuthorize, createBuildingInPark)
router.Put("/park/:pid/building/:bid", security.EnterpriseAuthorize, modifySpecificBuildingInPark)
router.Delete("/park/:pid/building/:bid", security.EnterpriseAuthorize, deletedParkBuilding)
router.Put("/park/:pid/building/:bid/enabled", security.EnterpriseAuthorize, modifyParkBuildingEnabling)
}
func ensureParkBelongs(c *fiber.Ctx, result *response.Result, requestParkId string) (bool, error) {
userSession, err := _retreiveSession(c)
if err != nil {
return false, result.Unauthorized(err.Error())
}
sure, err := service.ParkService.EnsurePark(userSession.Uid, requestParkId)
if err != nil {
return false, result.Error(http.StatusInternalServerError, err.Error())
}
if !sure {
return false, result.Unauthorized("不能访问不属于自己的园区。")
}
return true, nil
}
func listAllParksUnderSessionUser(c *fiber.Ctx) error {
// 列出隶属于当前用户的全部园区
func listParksBelongsToCurrentUser(c *fiber.Ctx) error {
result := response.NewResult(c)
userSession, err := _retreiveSession(c)
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("列出当前用的全部园区,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
keyword := c.Query("keyword")
parks, err := service.ParkService.ListAllParkBelongsTo(userSession.Uid, keyword)
parkLog.Info("列出当前用户下的全部园区", zap.String("user id", session.Uid))
parks, err := repository.ParkRepository.ListAllParks(session.Uid)
if err != nil {
parkLog.Error("无法获取园区列表。", zap.String("user id", session.Uid))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Json(http.StatusOK, "已获取到指定用户下的园区", fiber.Map{"parks": parks})
return result.Success("已获取到指定用户下的园区", fiber.Map{"parks": parks})
}
func listAllParksUnderSpecificUser(c *fiber.Ctx) error {
// 列出隶属于指定用户的全部园区
func listParksBelongsTo(c *fiber.Ctx) error {
result := response.NewResult(c)
requestUserId := c.Params("uid")
keyword := c.Query("keyword")
parks, err := service.ParkService.ListAllParkBelongsTo(requestUserId, keyword)
userId := c.Params("uid")
parkLog.Info("列出指定用户下的全部园区", zap.String("user id", userId))
parks, err := repository.ParkRepository.ListAllParks(userId)
if err != nil {
parkLog.Error("无法获取园区列表。", zap.String("user id", userId))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Json(http.StatusOK, "已获取到指定用户下的园区", fiber.Map{"parks": parks})
}
type _ParkInfoFormData struct {
Name string `json:"name" form:"name"`
Region *string `json:"region" form:"region"`
Address *string `json:"address" form:"address"`
Contact *string `json:"contact" form:"contact"`
Phone *string `json:"phone" from:"phone"`
Area decimal.NullDecimal `json:"area" from:"area"`
Capacity decimal.NullDecimal `json:"capacity" from:"capacity"`
TenementQuantity decimal.NullDecimal `json:"tenement" from:"tenement"`
Category int8 `json:"category" form:"category"`
SubmeterType int8 `json:"submeter" form:"submeter"`
}
func createNewPark(c *fiber.Ctx) error {
result := response.NewResult(c)
userSession, err := _retreiveSession(c)
if err != nil {
return result.Unauthorized(err.Error())
}
formData := new(_ParkInfoFormData)
if err := c.BodyParser(formData); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
newPark := new(model.Park)
copier.Copy(newPark, formData)
newPark.Id = uuid.New().String()
newPark.UserId = userSession.Uid
nameAbbr := tools.PinyinAbbr(newPark.Name)
newPark.Abbr = &nameAbbr
newPark.Enabled = true
err = service.ParkService.SaveNewPark(*newPark)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Created("新园区完成创建。")
}
func modifyPark(c *fiber.Ctx) error {
result := response.NewResult(c)
userSession, err := _retreiveSession(c)
if err != nil {
return result.Unauthorized(err.Error())
}
requestParkId := c.Params("pid")
formData := new(_ParkInfoFormData)
if err := c.BodyParser(formData); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
park, err := service.ParkService.FetchParkDetail(requestParkId)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
if userSession.Uid != park.UserId {
return result.Unauthorized("不能修改不属于自己的园区。")
}
copier.Copy(park, formData)
nameAbbr := tools.PinyinAbbr(formData.Name)
park.Abbr = &nameAbbr
err = service.ParkService.UpdateParkInfo(park)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("指定园区资料已更新。")
return result.Success("已获取到指定用户下的园区", fiber.Map{"parks": parks})
}
// 获取指定园区的详细信息
func fetchParkDetail(c *fiber.Ctx) error {
result := response.NewResult(c)
requestParkId := c.Params("pid")
if ensure, err := ensureParkBelongs(c, &result, requestParkId); !ensure {
return err
}
park, err := service.ParkService.FetchParkDetail(requestParkId)
parkId := c.Params("pid")
parkLog.Info("获取指定园区的详细信息", zap.String("park id", parkId))
park, err := repository.ParkRepository.RetrieveParkDetail(parkId)
if err != nil {
parkLog.Error("无法获取园区信息。", zap.String("park id", parkId))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Json(http.StatusOK, "已获取到指定园区的信息", fiber.Map{"park": park})
return result.Success("已获取到指定园区的详细信息", fiber.Map{"park": park})
}
type _ParkStateFormData struct {
Enabled bool `json:"enabled" form:"enabled"`
}
func changeParkEnableState(c *fiber.Ctx) error {
// 创建一个新的园区
func createPark(c *fiber.Ctx) error {
result := response.NewResult(c)
userSession, err := _retreiveSession(c)
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("创建一个新的园区,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
requestParkId := c.Params("pid")
if ensure, err := ensureParkBelongs(c, &result, requestParkId); !ensure {
return err
parkLog.Info("创建一个新的园区", zap.String("user id", session.Uid))
creationForm := new(vo.ParkInformationForm)
if err := c.BodyParser(creationForm); err != nil {
parkLog.Error("无法解析园区表单数据。", zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
formData := new(_ParkStateFormData)
if err := c.BodyParser(formData); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
err = service.ParkService.ChangeParkState(userSession.Uid, requestParkId, formData.Enabled)
park, err := creationForm.TryIntoPark()
if err != nil {
parkLog.Error("无法将园区表单数据转换为园区对象。", zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
ok, err := repository.ParkRepository.CreatePark(session.Uid, park)
switch {
case err == nil && !ok:
parkLog.Error("无法创建新的园区。", zap.String("user id", session.Uid))
return result.NotAccept("无法创建新的园区。")
case err != nil:
parkLog.Error("无法创建新的园区。", zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("指定园区的可用性状态已成功更新。")
return result.Created("已创建一个新的园区")
}
// 修改指定园区的信息
func modifySpecificPark(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("修改指定园区的信息,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
if pass, err := checkParkBelongs(parkId, parkLog, c, &result); !pass {
return err
}
parkForm := new(vo.ParkInformationForm)
if err := c.BodyParser(parkForm); err != nil {
parkLog.Error("无法解析园区表单数据。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
park, err := parkForm.TryIntoPark()
if err != nil {
parkLog.Error("无法将园区表单数据转换为园区对象。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
ok, err := repository.ParkRepository.UpdatePark(parkId, park)
switch {
case err == nil && !ok:
parkLog.Error("无法更新园区信息。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.NotAccept("无法更新园区信息。")
case err != nil:
parkLog.Error("无法更新园区信息。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("已更新指定园区的详细信息")
}
// 修改指定园区的可用性
func modifyParkEnabling(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("修改指定园区的可用性,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
if pass, err := checkParkBelongs(parkId, parkLog, c, &result); !pass {
return err
}
stateForm := new(vo.StateForm)
if err := c.BodyParser(stateForm); err != nil {
parkLog.Error("无法解析园区表单数据。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
ok, err := repository.ParkRepository.EnablingPark(parkId, stateForm.Enabled)
switch {
case err == nil && !ok:
parkLog.Error("无法更新园区可用性。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.NotAccept("无法更新园区可用性。")
case err != nil:
parkLog.Error("无法更新园区可用性。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("已更新指定园区的可用性。")
}
// 删除指定的园区
func deleteSpecificPark(c *fiber.Ctx) error {
result := response.NewResult(c)
userSession, err := _retreiveSession(c)
parkId := c.Params("pid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("删除指定的园区,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
requestParkId := c.Params("pid")
if ensure, err := ensureParkBelongs(c, &result, requestParkId); !ensure {
if pass, err := checkParkBelongs(parkId, parkLog, c, &result); !pass {
return err
}
err = service.ParkService.DeletePark(userSession.Uid, requestParkId)
if err != nil {
ok, err := repository.ParkRepository.DeletePark(parkId)
switch {
case err == nil && !ok:
parkLog.Error("无法删除园区。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.NotAccept("无法删除园区。")
case err != nil:
parkLog.Error("无法删除园区。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Deleted("指定园区已成功删除。")
return result.Deleted("已删除指定园区")
}
// 列出指定园区中已经登记的建筑
func listBuildingsBelongsToPark(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("列出指定园区中已经登记的建筑,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
ok, err := repository.ParkRepository.IsParkBelongs(parkId, session.Uid)
switch {
case err != nil:
parkLog.Error("无法判断园区是否隶属于当前用户。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
case err == nil && !ok:
parkLog.Error("用户试图访问不属于自己的园区。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.Forbidden("您无权访问该园区。")
}
buildings, err := repository.ParkRepository.RetrieveParkBuildings(parkId)
if err != nil {
parkLog.Error("无法获取园区中的建筑列表。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success("已获取到指定园区中的建筑列表", fiber.Map{"buildings": buildings})
}
// 在指定园区中创建一个新的建筑
func createBuildingInPark(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("在指定园区中创建一个新的建筑,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
if pass, err := checkParkBelongs(parkId, parkLog, c, &result); !pass {
return err
}
buildingForm := new(vo.ParkBuildingInformationForm)
if err := c.BodyParser(buildingForm); err != nil {
parkLog.Error("无法解析建筑表单数据。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
ok, err := repository.ParkRepository.CreateParkBuilding(parkId, buildingForm.Name, &buildingForm.Floors)
switch {
case err == nil && !ok:
parkLog.Error("无法创建新的建筑。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.NotAccept("无法创建新的建筑。")
case err != nil:
parkLog.Error("无法创建新的建筑。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Created("已创建一个新的建筑")
}
// 修改指定园区中的指定建筑的信息
func modifySpecificBuildingInPark(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
buildingId := c.Params("bid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("修改指定园区中的指定建筑的信息,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
if pass, err := checkParkBelongs(parkId, parkLog, c, &result); !pass {
return err
}
buildingForm := new(vo.ParkBuildingInformationForm)
if err := c.BodyParser(buildingForm); err != nil {
parkLog.Error("无法解析建筑表单数据。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
ok, err := repository.ParkRepository.ModifyParkBuilding(buildingId, parkId, buildingForm.Name, &buildingForm.Floors)
switch {
case err == nil && !ok:
parkLog.Error("无法更新建筑信息。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.NotAccept("无法更新建筑信息。")
case err != nil:
parkLog.Error("无法更新建筑信息。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("已更新指定建筑的信息")
}
// 修改指定园区中指定建筑的可用性
func modifyParkBuildingEnabling(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
buildingId := c.Params("bid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("修改指定园区中指定建筑的可用性,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
if pass, err := checkParkBelongs(parkId, parkLog, c, &result); !pass {
return err
}
stateForm := new(vo.StateForm)
if err := c.BodyParser(stateForm); err != nil {
parkLog.Error("无法解析建筑表单数据。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.NotAccept(err.Error())
}
ok, err := repository.ParkRepository.EnablingParkBuilding(buildingId, parkId, stateForm.Enabled)
switch {
case err == nil && !ok:
parkLog.Error("无法更新建筑可用性。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.NotAccept("无法更新建筑可用性。")
case err != nil:
parkLog.Error("无法更新建筑可用性。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("已更新指定建筑的可用性")
}
// 删除指定园区中的指定建筑
func deletedParkBuilding(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
buildingId := c.Params("bid")
session, err := _retreiveSession(c)
if err != nil {
parkLog.Error("删除指定园区中的指定建筑,无法获取当前用户的会话。")
return result.Unauthorized(err.Error())
}
if pass, err := checkParkBelongs(parkId, parkLog, c, &result); !pass {
return err
}
ok, err := repository.ParkRepository.DeleteParkBuilding(buildingId, parkId)
switch {
case err == nil && !ok:
parkLog.Error("无法删除建筑。", zap.String("park id", parkId), zap.String("user id", session.Uid))
return result.NotAccept("无法删除建筑。")
case err != nil:
parkLog.Error("无法删除建筑。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Deleted("已删除指定的建筑")
}

View File

@@ -1,22 +1,22 @@
package controller
import (
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/service"
"net/http"
"github.com/gofiber/fiber/v2"
)
func InitializeRegionController(router *fiber.App) {
router.Get("/region/:rid", fetchRegions)
router.Get("/regions/:rid", fetchAllLeveledRegions)
func InitializeRegionHandlers(router *fiber.App) {
router.Get("/region/:rid", getSubRegions)
router.Get("/regions/:rid", getParentRegions)
}
func fetchRegions(c *fiber.Ctx) error {
func getSubRegions(c *fiber.Ctx) error {
result := response.NewResult(c)
requestParentId := c.Params("rid")
regions, err := service.RegionService.FetchSubRegions(requestParentId)
regions, err := repository.RegionRepository.FindSubRegions(requestParentId)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
@@ -26,10 +26,10 @@ func fetchRegions(c *fiber.Ctx) error {
return result.Json(http.StatusOK, "已经获取到相关的行政区划。", fiber.Map{"regions": regions})
}
func fetchAllLeveledRegions(c *fiber.Ctx) error {
func getParentRegions(c *fiber.Ctx) error {
result := response.NewResult(c)
requestRegionCode := c.Params("rid")
regions, err := service.RegionService.FetchAllParentRegions(requestRegionCode)
regions, err := repository.RegionRepository.FindParentRegions(requestRegionCode)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}

View File

@@ -1,301 +1,424 @@
package controller
import (
"electricity_bill_calc/exceptions"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/tools"
"net/http"
"strconv"
"time"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
"github.com/samber/lo"
"github.com/shopspring/decimal"
"go.uber.org/zap"
)
func InitializeReportController(router *fiber.App) {
router.Get("/reports/with/drafts", security.EnterpriseAuthorize, fetchNewestReportOfParkWithDraft)
router.Post("/park/:pid/report", security.EnterpriseAuthorize, initializeNewReport)
router.Get("/report/:rid/step/state", security.EnterpriseAuthorize, fetchReportStepStates)
router.Get("/report/:rid/summary", security.EnterpriseAuthorize, fetchReportParkSummary)
router.Put("/report/:rid/summary", security.EnterpriseAuthorize, fillReportSummary)
router.Get("/report/:rid/summary/calculate", security.EnterpriseAuthorize, testCalculateReportSummary)
router.Post("/report/:rid/summary/calculate", security.EnterpriseAuthorize, progressReportSummary)
router.Put("/report/:rid/step/meter/register", security.EnterpriseAuthorize, progressEndUserRegister)
var reportLog = logger.Named("Handler", "Report")
func InitializeReportHandlers(router *fiber.App) {
router.Get("/reports", security.MustAuthenticated, reportComprehensiveSearch)
router.Post("/report", security.EnterpriseAuthorize, initNewReportCalculateTask)
router.Get("/report/draft", security.EnterpriseAuthorize, listDraftReportIndicies)
router.Post("/report/calcualte", security.EnterpriseAuthorize, testCalculateReportSummary)
router.Get("/report/calculate/status", security.EnterpriseAuthorize, listCalculateTaskStatus)
router.Get("/report/:rid", security.EnterpriseAuthorize, getReportDetail)
router.Put("/report/:rid", security.EnterpriseAuthorize, updateReportCalculateTask)
router.Post("/report/:rid/publish", security.EnterpriseAuthorize, publishReport)
router.Get("/reports", security.MustAuthenticated, searchReports)
router.Get("/report/:rid", security.MustAuthenticated, fetchReportPublicity)
router.Post("/report/:rid/calculate", security.EnterpriseAuthorize, calculateReport)
router.Put("/report/:rid/calculate", security.EnterpriseAuthorize, initiateCalculateTask)
router.Get("/report/:rid/publics", security.MustAuthenticated, listPublicMetersInReport)
router.Get("/report/:rid/summary", security.MustAuthenticated, getReportSummary)
router.Get("/report/:rid/summary/filled", security.EnterpriseAuthorize, getParkFilledSummary)
router.Get("/report/:rid/pooled", security.MustAuthenticated, listPooledMetersInReport)
router.Get("/report/:rid/pooled/:code/submeter", security.MustAuthenticated, listSubmetersInPooledMeter)
router.Get("/report/:rid/tenement", security.MustAuthenticated, listTenementsInReport)
router.Get("/report/:rid/tenement/:tid", security.MustAuthenticated, getTenementDetailInReport)
}
func ensureReportBelongs(c *fiber.Ctx, result *response.Result, requestReportId string) (bool, error) {
_, err := _retreiveSession(c)
// 检查指定报表是否属于当前用户
func checkReportBelongs(reportId string, log *zap.Logger, c *fiber.Ctx, result *response.Result) (bool, error) {
session, err := _retreiveSession(c)
if err != nil {
return false, result.Unauthorized(err.Error())
log.Error("无法获取当前用户的会话信息", zap.Error(err))
return false, result.Unauthorized("无法获取当前用户的会话信息。")
}
requestReport, err := service.ReportService.RetreiveReportIndex(requestReportId)
ok, err := repository.ReportRepository.IsBelongsTo(reportId, session.Uid)
if err != nil {
return false, result.NotFound(err.Error())
log.Error("无法检查核算报表的所有权", zap.Error(err))
return false, result.Error(fiber.StatusInternalServerError, "无法检查核算报表的所有权。")
}
if requestReport == nil {
return false, result.NotFound("指定报表未能找到。")
if !ok {
log.Error("核算报表不属于当前用户")
return false, result.Forbidden("核算报表不属于当前用户。")
}
return ensureParkBelongs(c, result, requestReport.ParkId)
return true, nil
}
func fetchNewestReportOfParkWithDraft(c *fiber.Ctx) error {
// 获取当前登录用户下所有园区的尚未发布的核算报表索引
func listDraftReportIndicies(c *fiber.Ctx) error {
result := response.NewResult(c)
userSession, err := _retreiveSession(c)
session, err := _retreiveSession(c)
if err != nil {
return result.Unauthorized(err.Error())
reportLog.Error("无法获取当前用户的会话信息", zap.Error(err))
return result.Unauthorized("无法获取当前用户的会话信息。")
}
parks, err := service.ReportService.FetchParksWithNewestReport(userSession.Uid)
reportLog.Info("检索指定用户下的未发布核算报表索引", zap.String("User", session.Uid))
indicies, err := service.ReportService.ListDraftReportIndicies(session.Uid)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
reportLog.Error("无法获取当前用户的核算报表索引", zap.Error(err))
return result.NotFound("当前用户下未找到核算报表索引。")
}
return result.Json(http.StatusOK, "已获取到指定用户下所有园区的最新报表记录。", fiber.Map{"parks": parks})
return result.Success(
"已经获取到指定用户的报表索引。",
fiber.Map{"reports": indicies},
)
}
func initializeNewReport(c *fiber.Ctx) error {
// 初始化一个新的核算任务
func initNewReportCalculateTask(c *fiber.Ctx) error {
result := response.NewResult(c)
requestParkId := c.Params("pid")
userSession, err := _retreiveSession(c)
session, err := _retreiveSession(c)
if err != nil {
return result.Unauthorized(err.Error())
reportLog.Error("无法获取当前用户的会话信息", zap.Error(err))
return result.Unauthorized("无法获取当前用户的会话信息。")
}
if ensure, err := ensureParkBelongs(c, &result, requestParkId); !ensure {
reportLog.Info("初始化指定用户的一个新核算任务", zap.String("User", session.Uid))
var form vo.ReportCreationForm
if err := c.BodyParser(&form); err != nil {
reportLog.Error("无法解析创建核算报表的请求数据。", zap.Error(err))
return result.BadRequest("无法解析创建核算报表的请求数据。")
}
if pass, err := checkParkBelongs(form.Park, reportLog, c, &result); !pass {
return err
}
requestPeriod := c.Query("period")
reportPeriod, err := time.Parse("2006-01", requestPeriod)
ok, err := repository.ReportRepository.CreateReport(&form)
if err != nil {
return result.NotAccept("提供的初始化期数格式不正确。")
reportLog.Error("无法创建核算报表", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法创建核算报表。")
}
valid, err := service.ReportService.IsNewPeriodValid(userSession.Uid, requestParkId, reportPeriod)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
if !ok {
reportLog.Error("未能完成核算报表的保存。")
return result.NotAccept("未能完成核算报表的保存。")
}
if !valid {
return result.NotAccept("只能初始化已发布报表下一个月份的新报表。")
}
newId, err := service.ReportService.InitializeNewReport(requestParkId, reportPeriod)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Created("新一期报表初始化成功。", fiber.Map{"reportId": newId})
return result.Success("已经成功创建核算报表。")
}
func fetchReportStepStates(c *fiber.Ctx) error {
// 更新指定的核算任务
func updateReportCalculateTask(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
reportId := c.Params("rid")
if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass {
return err
}
requestReport, err := service.ReportService.RetreiveReportIndex(requestReportId)
if err != nil {
return result.NotFound(err.Error())
var form vo.ReportModifyForm
if err := c.BodyParser(&form); err != nil {
reportLog.Error("无法解析更新核算报表的请求数据。", zap.Error(err))
return result.BadRequest("无法解析更新核算报表的请求数据。")
}
return result.Json(http.StatusOK, "已经获取到指定报表的填写状态。", fiber.Map{"steps": requestReport.StepState})
ok, err := repository.ReportRepository.UpdateReportSummary(reportId, &form)
if err != nil {
reportLog.Error("无法更新核算报表", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法更新核算报表。")
}
if !ok {
reportLog.Error("未能完成核算报表的更新。")
return result.NotAccept("未能完成核算报表的更新。")
}
return result.Success("已经成功更新核算报表。")
}
func fetchReportParkSummary(c *fiber.Ctx) error {
// 启动指定的核算任务
func initiateCalculateTask(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
reportId := c.Params("rid")
if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass {
return err
}
summary, err := service.ReportService.RetreiveReportSummary(requestReportId)
err := service.ReportService.DispatchReportCalculate(reportId)
if err != nil {
return result.NotFound(err.Error())
reportLog.Error("无法启动核算报表计算任务", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法启动核算报表计算任务。")
}
return result.Success("已经成功启动核算报表计算任务。")
}
// 获取自己园区的已经填写的园区电量信息
func getParkFilledSummary(c *fiber.Ctx) error {
result := response.NewResult(c)
reportId := c.Params("rid")
if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass {
return err
}
reportLog.Info("获取园区电量信息", zap.String("Report", reportId))
summary, err := repository.ReportRepository.RetrieveReportSummary(reportId)
if err != nil {
reportLog.Error("无法获取核算报表的园区电量信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表的园区电量信息。")
}
if summary == nil {
return result.NotFound("指定报表未能找到。")
reportLog.Error("未找到核算报表的园区电量信息")
return result.NotFound("未找到核算报表的园区电量信息。")
}
return result.Json(http.StatusOK, "已经获取到指定报表中的园区概况。", fiber.Map{"summary": summary})
}
type ReportSummaryFormData struct {
Overall decimal.Decimal `json:"overall" form:"overall"`
OverallFee decimal.Decimal `json:"overallFee" form:"overallFee"`
Critical decimal.Decimal `json:"critical" form:"critical"`
CriticalFee decimal.Decimal `json:"criticalFee" form:"criticalFee"`
Peak decimal.Decimal `json:"peak" form:"peak"`
PeakFee decimal.Decimal `json:"peakFee" form:"peakFee"`
Valley decimal.Decimal `json:"valley" form:"valley"`
ValleyFee decimal.Decimal `json:"valleyFee" form:"valleyFee"`
BasicFee decimal.Decimal `json:"basicFee" form:"basicFee"`
AdjustFee decimal.Decimal `json:"adjustFee" from:"adjustFee"`
}
func fillReportSummary(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
return err
}
formData := new(ReportSummaryFormData)
if err := c.BodyParser(formData); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
originSummary, err := service.ReportService.RetreiveReportSummary(requestReportId)
if err != nil {
return result.NotFound(err.Error())
}
copier.Copy(originSummary, formData)
originSummary.ReportId = requestReportId
err = service.ReportService.UpdateReportSummary(originSummary)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("指定电费公示报表中的园区概况基本数据已经完成更新。")
var summaryResponse vo.SimplifiedReportSummary
copier.Copy(&summaryResponse, summary)
return result.Success(
"已经获取到核算报表的园区电量信息。",
fiber.Map{"summary": summaryResponse},
)
}
// 对提供的园区电量信息进行试计算,返回试计算结果
func testCalculateReportSummary(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
return err
reportLog.Info("试计算园区电量信息")
var form vo.TestCalculateForm
if err := c.BodyParser(&form); err != nil {
reportLog.Error("无法解析试计算核算报表的请求数据。", zap.Error(err))
return result.BadRequest("无法解析试计算核算报表的请求数据。")
}
summary, err := service.ReportService.RetreiveReportSummary(requestReportId)
return result.Success(
"电量电费试计算已经完成。",
fiber.Map{"summary": form.Calculate()},
)
}
// 获取指定园区中尚未发布的核算报表计算状态
func listCalculateTaskStatus(c *fiber.Ctx) error {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
return result.NotFound(err.Error())
reportLog.Error("无法获取当前用户的会话信息", zap.Error(err))
return result.Unauthorized("无法获取当前用户的会话信息。")
}
summary.CalculatePrices()
calcResults := tools.ConvertStructToMap(summary)
return result.Json(
http.StatusOK,
"已完成园区概况的试计算。",
status, err := repository.ReportRepository.GetReportTaskStatus(session.Uid)
if err != nil {
reportLog.Error("无法获取核算报表计算状态", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表计算状态。")
}
statusResponse := make([]*vo.ReportCalculateTaskStatusResponse, 0)
copier.Copy(&statusResponse, &status)
return result.Success(
"已经获取到核算报表计算状态。",
fiber.Map{"status": statusResponse},
)
}
// 获取指定报表的详细信息
func getReportDetail(c *fiber.Ctx) error {
result := response.NewResult(c)
reportId := c.Params("rid")
reportLog.Info("获取核算报表的详细信息", zap.String("Report", reportId))
user, park, report, err := service.ReportService.RetrieveReportIndexDetail(reportId)
if err != nil {
reportLog.Error("无法获取核算报表的详细信息", zap.Error(err))
return result.NotFound("无法获取核算报表的详细信息。")
}
return result.Success(
"已经获取到核算报表的详细信息。",
fiber.Map{
"result": lo.PickByKeys(
calcResults,
[]string{"overallPrice", "criticalPrice", "peakPrice", "flat", "flatFee", "flatPrice", "valleyPrice", "consumptionFee"},
),
"detail": vo.NewReportDetailQueryResponse(user, park, report),
},
)
}
func progressReportSummary(c *fiber.Ctx) error {
// 获取指定核算报表的总览信息
func getReportSummary(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
return err
}
err := service.ReportService.CalculateSummaryAndFinishStep(requestReportId)
reportId := c.Params("rid")
report, err := repository.ReportRepository.RetrieveReportSummary(reportId)
if err != nil {
if nfErr, ok := err.(exceptions.NotFoundError); ok {
return result.NotFound(nfErr.Error())
} else {
return result.Error(http.StatusInternalServerError, err.Error())
}
reportLog.Error("无法获取核算报表的总览信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表的总览信息。")
}
return result.Success("已经完成园区概况的计算,并可以进行到下一步骤。")
}
func progressEndUserRegister(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
return err
}
report, err := service.ReportService.RetreiveReportIndex(requestReportId)
if err != nil {
return result.NotFound(err.Error())
}
err = service.ReportService.ProgressReportRegisterEndUser(*report)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success("终端用户抄表编辑步骤已经完成。")
}
func publishReport(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
return err
}
report, err := service.ReportService.RetreiveReportIndex(requestReportId)
if err != nil {
return result.NotFound(err.Error())
}
err = service.ReportService.PublishReport(*report)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success("指定的公示报表已经发布。")
}
func searchReports(c *fiber.Ctx) error {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
return result.Unauthorized(err.Error())
}
requestUser := lo.
If(session.Type == model.USER_TYPE_ENT, session.Uid).
Else(c.Query("user"))
requestPark := c.Query("park")
if len(requestPark) > 0 && session.Type == model.USER_TYPE_ENT {
if ensure, err := ensureParkBelongs(c, &result, requestPark); !ensure {
return err
}
}
requestPeriodString := c.Query("period")
var requestPeriod *time.Time = nil
if len(requestPeriodString) > 0 {
parsedPeriod, err := time.Parse("2006-01", requestPeriodString)
if err != nil {
return result.NotAccept("参数[period]的格式不正确。")
}
requestPeriod = lo.ToPtr(parsedPeriod)
}
requestKeyword := c.Query("keyword")
requestPage, err := strconv.Atoi(c.Query("page", "1"))
if err != nil {
return result.NotAccept("查询参数[page]格式不正确。")
}
requestAllReports, err := strconv.ParseBool(c.Query("all", "false"))
if err != nil {
return result.NotAccept("查询参数[all]格式不正确。")
}
records, totalItems, err := service.ReportService.SearchReport(requestUser, requestPark, requestKeyword, requestPeriod, requestPage, !requestAllReports)
if err != nil {
return result.NotFound(err.Error())
if report == nil {
reportLog.Error("未找到核算报表的总览信息")
return result.NotFound("未找到核算报表的总览信息。")
}
var summaryResponse vo.ParkSummaryResponse
copier.Copy(&summaryResponse, report)
return result.Success(
"已经取得符合条件的公示报表记录。",
response.NewPagedResponse(requestPage, totalItems).ToMap(),
fiber.Map{"reports": records},
"已经获取到核算报表的总览信息。",
fiber.Map{"summary": summaryResponse},
)
}
func fetchReportPublicity(c *fiber.Ctx) error {
// 获取指定报表中分页的公共表计的核算摘要信息
func listPublicMetersInReport(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
publicity, err := service.ReportService.AssembleReportPublicity(requestReportId)
reportId := c.Params("rid")
reportLog.Info("获取核算报表中的公共表计信息", zap.String("Report", reportId))
page := c.QueryInt("page", 1)
keyword := tools.EmptyToNil(c.Query("keyword"))
meters, total, err := repository.ReportRepository.ListPublicMetersInReport(reportId, uint(page), keyword)
if err != nil {
if nfErr, ok := err.(exceptions.NotFoundError); ok {
return result.NotFound(nfErr.Error())
} else {
return result.Error(http.StatusInternalServerError, err.Error())
}
reportLog.Error("无法获取核算报表中的公共表计信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的公共表计信息。")
}
return result.Success("已经取得指定公示报表的发布版本。", tools.ConvertStructToMap(publicity))
meterResponse := lo.Map(meters, func(meter *model.ReportDetailedPublicConsumption, _ int) *vo.ReportPublicQueryResponse {
m := &vo.ReportPublicQueryResponse{}
m.FromReportDetailPublicConsumption(meter)
return m
})
return result.Success(
"已经获取到指定核算报表中的分页公共表计的核算信息。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"public": meterResponse},
)
}
func calculateReport(c *fiber.Ctx) error {
// 获取指定报表中的分页的公摊表计的核算摘要信息
func listPooledMetersInReport(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
reportId := c.Params("rid")
reportLog.Info("获取核算报表中的公摊表计信息", zap.String("Report", reportId))
page := c.QueryInt("page", 1)
keyword := tools.EmptyToNil(c.Query("keyword"))
meters, total, err := repository.ReportRepository.ListPooledMetersInReport(reportId, uint(page), keyword)
if err != nil {
reportLog.Error("无法获取核算报表中的公摊表计信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的公摊表计信息。")
}
meterResponse := lo.Map(meters, func(meter *model.ReportDetailedPooledConsumption, _ int) *vo.ReportPooledQueryResponse {
m := &vo.ReportPooledQueryResponse{}
m.FromReportDetailPooledConsumption(meter)
return m
})
return result.Success(
"已经获取到指定核算报表中的分页公摊表计的核算信息。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"pooled": meterResponse},
)
}
// 列出指定报表中指定公共表计下各个分摊表计的消耗数据
func listSubmetersInPooledMeter(c *fiber.Ctx) error {
result := response.NewResult(c)
reportId := c.Params("rid")
meterId := c.Params("code")
if len(meterId) == 0 {
reportLog.Error("未提供公共表计的编号")
return result.BadRequest("未提供公共表计的编号。")
}
meters, err := repository.ReportRepository.ListPooledMeterDetailInReport(reportId, meterId)
if err != nil {
reportLog.Error("无法获取核算报表中的公共表计信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的公共表计信息。")
}
meterResponse := lo.Map(meters, func(meter *model.ReportDetailNestedMeterConsumption, _ int) *vo.ReportPooledQueryResponse {
m := &vo.ReportPooledQueryResponse{}
m.FromReportDetailNestedMeterConsumption(meter)
return m
})
return result.Success(
"已经获取到指定核算报表中的公共表计的核算信息。",
fiber.Map{"meters": meterResponse},
)
}
// 获取指定报表中分页的商户核算电量电费概要数据
func listTenementsInReport(c *fiber.Ctx) error {
result := response.NewResult(c)
reportId := c.Params("rid")
page := c.QueryInt("page", 1)
keyword := tools.EmptyToNil(c.Query("keyword"))
tenements, total, err := repository.ReportRepository.ListTenementInReport(reportId, uint(page), keyword)
if err != nil {
reportLog.Error("无法获取核算报表中的商户信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的商户信息。")
}
tenementsResponse := lo.Map(tenements, func(tenement *model.ReportTenement, _ int) *vo.ReportTenementSummaryResponse {
t := &vo.ReportTenementSummaryResponse{}
t.FromReportTenement(tenement)
return t
})
return result.Success(
"已经获取到指定核算报表中的分页商户的核算信息。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"tenements": tenementsResponse},
)
}
// 获取指定报表中指定商户的详细核算信息
func getTenementDetailInReport(c *fiber.Ctx) error {
result := response.NewResult(c)
reportId := c.Params("rid")
tenementId := c.Params("tid")
detail, err := repository.ReportRepository.GetTenementDetailInReport(reportId, tenementId)
if err != nil {
reportLog.Error("无法获取核算报表中的商户信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的商户信息。")
}
var detailResponse vo.ReportTenementDetailResponse
detailResponse.FromReportTenement(detail)
return result.Success(
"已经获取到指定核算报表中的商户的详细核算信息。",
fiber.Map{"detail": detailResponse},
)
}
// 发布指定的核算报表
func publishReport(c *fiber.Ctx) error {
result := response.NewResult(c)
reportId := c.Params("rid")
if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass {
return err
}
err := service.CalculateService.ComprehensivelyCalculateReport(requestReportId)
ok, err := repository.ReportRepository.PublishReport(reportId)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
reportLog.Error("无法发布核算报表", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "发布核算报表出错。")
}
return result.Success("指定公示报表中的数据已经计算完毕。")
if !ok {
reportLog.Error("未能完成核算报表的发布。")
return result.NotAccept("未能完成核算报表的发布。")
}
return result.Success("已经成功发布核算报表。")
}
// 对核算报表进行综合检索
func reportComprehensiveSearch(c *fiber.Ctx) error {
result := response.NewResult(c)
user := tools.EmptyToNil(c.Query("user"))
session, err := _retreiveSession(c)
if err != nil {
reportLog.Error("无法获取当前用户的会话信息", zap.Error(err))
return result.Unauthorized("无法获取当前用户的会话信息。")
}
park := tools.EmptyToNil(c.Query("park_id"))
if session.Type == model.USER_TYPE_ENT && park != nil && len(*park) > 0 {
if pass, err := checkParkBelongs(*park, reportLog, c, &result); !pass {
return err
}
}
var requestUser *string
if session.Type == model.USER_TYPE_ENT {
requestUser = lo.ToPtr(tools.DefaultTo(user, session.Uid))
} else {
requestUser = user
}
page := c.QueryInt("page", 1)
keyword := tools.EmptyToNil(c.Query("keyword"))
startDate, err := types.ParseDatep(c.Query("period_start"))
if err != nil {
reportLog.Error("无法解析核算报表查询的开始日期", zap.Error(err))
return result.BadRequest("无法解析核算报表查询的开始日期。")
}
endDate, err := types.ParseDatep(c.Query("period_end"))
if err != nil {
reportLog.Error("无法解析核算报表查询的结束日期", zap.Error(err))
return result.BadRequest("无法解析核算报表查询的结束日期。")
}
reports, total, err := service.ReportService.QueryReports(requestUser, park, uint(page), keyword, startDate, endDate)
if err != nil {
reportLog.Error("无法查询核算报表", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法查询核算报表。")
}
return result.Success(
"已经获取到指定核算报表的分页信息。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"reports": reports},
)
}

121
controller/sync.go Normal file
View File

@@ -0,0 +1,121 @@
package controller
import (
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/tools"
"electricity_bill_calc/vo"
"fmt"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
var synchronizeLog = logger.Named("Handler", "Synchronize")
func InitializeSynchronizeHandlers(router *fiber.App) {
router.Get("/synchronize/task", security.EnterpriseAuthorize, searchSynchronizeSchedules)
router.Get("/synchronize/configuration", security.EnterpriseAuthorize, getSynchronizeConfiguration)
router.Post("/synchronize/configuration", security.EnterpriseAuthorize, recordsynchronizeConfiguration)
}
// 查询当前平台中符合查询条件的同步任务企业用户无论传入什么用户ID条件都仅能看到自己的同步任务
func searchSynchronizeSchedules(c *fiber.Ctx) error {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
synchronizeLog.Error("查询同步任务失败,未能获取当前用户会话信息", zap.Error(err))
return result.Unauthorized("未能获取当前用户会话信息。")
}
parkId := tools.EmptyToNil(c.Params("park"))
if parkId != nil && len(*parkId) > 0 {
if pass, err := checkParkBelongs(*parkId, reportLog, c, &result); !pass {
return err
}
}
userId := tools.EmptyToNil(c.Params("user"))
keyword := tools.EmptyToNil(c.Query("keyword"))
page := c.QueryInt("page", 1)
synchronizeLog.Info("查询当前平台中符合查询条件的同步任务。", zap.String("Ent", session.Uid), zap.Stringp("Park", parkId))
schedules, total, err := repository.SynchronizeRepository.SearchSynchronizeSchedules(userId, parkId, uint(page), keyword)
if err != nil {
reportLog.Error("无法获取同步任务", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取同步任务")
}
return result.Success(
" ",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"tasks": schedules},
)
}
// 获取指定的同步任务配置
func getSynchronizeConfiguration(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Query("park")
userId := c.Query("user")
session, err := _retreiveSession(c)
if err != nil {
reportLog.Error("无法获取当前用户的会话信息", zap.Error(err))
return result.Unauthorized("无法获取当前用户的会话信息。")
}
var user_id string
if session.Type == model.USER_TYPE_ENT {
user_id = session.Uid
} else {
if userId != "" {
user_id = userId
} else {
return result.NotAccept(fmt.Sprintf("必须指定要记录同步任务的用户,%s", err.Error()))
}
}
fmt.Println("pppppppppppppppppppppppppppp", parkId, len(parkId))
if parkId == "" {
return result.NotAccept("必须指定要获取同步任务的园区。")
}
fmt.Printf(user_id)
configurations, err := repository.SynchronizeRepository.RetrieveSynchronizeConfiguration(user_id, parkId)
if err != nil {
reportLog.Error("无法获取同步任务", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取同步任务")
}
return result.Success(
" 123",
fiber.Map{"setup": configurations},
)
}
func recordsynchronizeConfiguration(c *fiber.Ctx) error {
userId := c.Query("user")
synchronizeLog.Info("记录一个新的同步任务配置", zap.String("user id", userId))
session, err := _retreiveSession(c)
result := response.NewResult(c)
if err != nil {
reportLog.Error("无法获取当前用户的会话信息", zap.Error(err))
return result.Unauthorized("无法获取当前用户的会话信息。")
}
var Form vo.SynchronizeConfigurationCreateForm
if err := c.BodyParser(&Form); err != nil {
meterLog.Error("无法更新同步配置,无法解析表计更新表单", zap.Error(err))
return result.NotAccept(err.Error())
}
var user_id string
if session.Type == model.USER_TYPE_ENT {
user_id = session.Uid
} else {
if userId != "" {
user_id = userId
} else {
return result.NotAccept(fmt.Sprintf("必须指定更新同步任务的用户,%s", err.Error()))
}
}
//configurations, err := repository.SynchronizeRepository.CreateSynchronizeConfiguration
if err := service.SynchronizeService.CreateSynchronizeConfiguration(user_id, &Form); err != nil {
synchronizeLog.Error("无法更新同步配置", zap.Error(err))
return result.NotAccept(err.Error())
}
return result.Success("更新完成。")
}

286
controller/tenement.go Normal file
View File

@@ -0,0 +1,286 @@
package controller
import (
"electricity_bill_calc/logger"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/tools"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
"github.com/samber/lo"
"go.uber.org/zap"
)
var tenementLog = logger.Named("Handler", "Tenement")
func InitializeTenementHandler(router *fiber.App) {
router.Get("/tenement/choice", security.EnterpriseAuthorize, listTenementForChoice)
router.Get("/tenement/:pid", security.EnterpriseAuthorize, listTenement)
router.Put("/tenement/:pid/:tid", security.EnterpriseAuthorize, updateTenement)
router.Get("/tenement/:pid/:tid", security.EnterpriseAuthorize, getTenementDetail)
router.Get("/tenement/:pid/:tid/meter", security.EnterpriseAuthorize, listMeters)
router.Post("/tenement/:pid/:tid/move/out", security.EnterpriseAuthorize, moveOutTenement)
router.Post("/tenement/:pid", security.EnterpriseAuthorize, addTenement)
router.Post("/tenement/:pid/:tid/binding", security.EnterpriseAuthorize, bindMeterToTenement)
router.Post("/tenement/:pid/:tid/binding/:code/unbind", security.EnterpriseAuthorize, unbindMeterFromTenement)
}
// 列出园区中的商户
func listTenement(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
tenementLog.Info("列出园区中的商户", zap.String("Park", parkId))
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
page := c.QueryInt("page", 1)
keyword := tools.EmptyToNil(c.Query("keyword"))
building := tools.EmptyToNil(c.Query("building"))
startDate, err := types.ParseDatep(c.Query("startDate"))
if err != nil {
tenementLog.Error("列出园区中的商户失败,未能解析查询开始日期", zap.Error(err))
return result.BadRequest(err.Error())
}
endDate, err := types.ParseDatep(c.Query("endDate"))
if err != nil {
tenementLog.Error("列出园区中的商户失败,未能解析查询结束日期", zap.Error(err))
return result.BadRequest(err.Error())
}
state := c.QueryInt("state", 0)
tenements, total, err := repository.TenementRepository.ListTenements(parkId, uint(page), keyword, building, startDate, endDate, state)
if err != nil {
tenementLog.Error("列出园区中的商户失败,未能获取商户列表", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, err.Error())
}
tenementsResponse := make([]*vo.TenementQueryResponse, 0)
copier.Copy(&tenementsResponse, &tenements)
return result.Success(
"已经获取到要查询的商户。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{
"tenements": tenementsResponse,
},
)
}
// 列出指定商户下所有的表计
func listMeters(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
tenementId := c.Params("tid")
tenementLog.Info("列出指定商户下所有的表计", zap.String("Park", parkId), zap.String("Tenement", tenementId))
meters, err := service.TenementService.ListMeter(parkId, tenementId)
if err != nil {
tenementLog.Error("列出指定商户下所有的表计失败,未能获取表计列表", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, err.Error())
}
return result.Success(
"已经获取到要查询的表计。",
fiber.Map{
"meters": meters,
},
)
}
// 增加一个新的商户
func addTenement(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
tenementLog.Info("增加一个新的商户", zap.String("Park", parkId))
var form vo.TenementCreationForm
if err := c.BodyParser(&form); err != nil {
tenementLog.Error("增加一个新的商户失败,未能解析要添加的商户信息", zap.Error(err))
return result.BadRequest(fmt.Sprintf("无法解析要添加的商户信息,%s", err.Error()))
}
err := service.TenementService.CreateTenementRecord(parkId, &form)
if err != nil {
tenementLog.Error("增加一个新的商户失败,未能添加商户记录", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法添加商户记录,%s", err.Error()))
}
return result.Success("已经成功添加商户。")
}
// 给指定商户绑定一个新的表计
func bindMeterToTenement(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
tenementId := c.Params("tid")
if len(tenementId) == 0 {
tenementLog.Error("给指定商户绑定一个新的表计失败,未指定商户。")
return result.BadRequest("未指定商户。")
}
tenementLog.Info("向指定商户绑定一个表计。", zap.String("Park", parkId), zap.String("Tenement", tenementId))
var form vo.MeterReadingFormWithCode
if err := c.BodyParser(&form); err != nil {
tenementLog.Error("给指定商户绑定一个新的表计失败,未能解析要绑定的表计信息", zap.Error(err))
return result.BadRequest(fmt.Sprintf("无法解析要绑定的表计信息,%s", err.Error()))
}
if !form.MeterReadingForm.Validate() {
tenementLog.Error("给指定商户绑定一个新的表计失败,表计读数不能正确配平,尖锋电量、峰电量、谷电量之和超过总电量。")
return result.NotAccept("表计读数不能正确配平,尖锋电量、峰电量、谷电量之和超过总电量。")
}
err := service.TenementService.BindMeter(parkId, tenementId, form.Code, &form.MeterReadingForm)
if err != nil {
tenementLog.Error("给指定商户绑定一个新的表计失败,未能绑定表计", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法绑定表计,%s", err.Error()))
}
return result.Success("已经成功绑定表计。")
}
// 从指定商户下解除一个表计的绑定
func unbindMeterFromTenement(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
tenementId := c.Params("tid")
if len(tenementId) == 0 {
tenementLog.Error("从指定商户下解除一个表计的绑定失败,未指定商户。")
return result.BadRequest("未指定商户。")
}
meterCode := c.Params("code")
if len(meterCode) == 0 {
tenementLog.Error("从指定商户下解除一个表计的绑定失败,未指定表计。")
return result.BadRequest("未指定表计。")
}
tenementLog.Info("从指定商户处解绑一个表计。", zap.String("Park", parkId), zap.String("Tenement", tenementId), zap.String("Meter", meterCode))
var form vo.MeterReadingForm
if err := c.BodyParser(&form); err != nil {
tenementLog.Error("从指定商户下解除一个表计的绑定失败,未能解析要解除绑定的表计抄表数据。", zap.Error(err))
return result.BadRequest(fmt.Sprintf("无法解析要解除绑定的表计抄表数据,%s", err.Error()))
}
err := service.TenementService.UnbindMeter(parkId, tenementId, meterCode, &form)
if err != nil {
tenementLog.Error("从指定商户下解除一个表计的绑定失败,未能解除绑定表计。", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法解除绑定表计,%s", err.Error()))
}
return result.Success("已经成功解除表计绑定。")
}
// 修改指定商户的详细信息
func updateTenement(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
tenementId := c.Params("tid")
if len(tenementId) == 0 {
tenementLog.Error("修改指定商户的详细信息失败,未指定商户。")
return result.BadRequest("未指定商户。")
}
tenementLog.Info("修改指定商户的详细信息。", zap.String("Park", parkId), zap.String("Tenement", tenementId))
var form vo.TenementCreationForm
if err := c.BodyParser(&form); err != nil {
tenementLog.Error("修改指定商户的详细信息失败,未能解析要修改的商户信息", zap.Error(err))
return result.BadRequest(fmt.Sprintf("无法解析要修改的商户信息,%s", err.Error()))
}
err := repository.TenementRepository.UpdateTenement(parkId, tenementId, &form)
if err != nil {
tenementLog.Error("修改指定商户的详细信息失败,未能修改商户信息", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法修改商户信息,%s", err.Error()))
}
return result.Success("商户信息修改成功。")
}
// 迁出指定园区中的商户
func moveOutTenement(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
tenementId := c.Params("tid")
if len(tenementId) == 0 {
tenementLog.Error("迁出指定园区中的商户失败,未指定商户。")
return result.BadRequest("未指定商户。")
}
tenementLog.Info("迁出指定园区中的商户。", zap.String("Park", parkId), zap.String("Tenement", tenementId))
var readings []*vo.MeterReadingFormWithCode
if err := c.BodyParser(&readings); err != nil {
tenementLog.Error("迁出指定园区中的商户失败,未能解析要迁出商户的抄表数据。", zap.Error(err))
return result.BadRequest(fmt.Sprintf("无法解析要迁出商户的抄表数据,%s", err.Error()))
}
err := service.TenementService.MoveOutTenement(parkId, tenementId, readings)
if err != nil {
tenementLog.Error("迁出指定园区中的商户失败,未能迁出商户。", zap.Error(err))
return result.NotAccept(fmt.Sprintf("无法迁出商户,%s", err.Error()))
}
return result.Success("商户迁出成功。")
}
// 列出园区中的商户列表,主要用于下拉列表
func listTenementForChoice(c *fiber.Ctx) error {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
tenementLog.Error("列出园区中的商户列表失败,未能获取当前用户会话信息", zap.Error(err))
return result.Unauthorized("未能获取当前用户会话信息。")
}
parkId := tools.EmptyToNil(c.Params("pid"))
if parkId != nil && len(*parkId) > 0 {
if pass, err := checkParkBelongs(*parkId, tenementLog, c, &result); !pass {
return err
}
}
tenementLog.Info("列出园区中的商户列表,主要用于下拉列表。", zap.String("Ent", session.Uid), zap.Stringp("Park", parkId))
keyword := tools.EmptyToNil(c.Query("keyword"))
limit := c.QueryInt("limit", 6)
tenements, err := repository.TenementRepository.ListForSelect(session.Uid, parkId, keyword, lo.ToPtr(uint(limit)))
if err != nil {
tenementLog.Error("列出园区中的商户列表失败,未能获取商户列表", zap.Error(err))
return result.NotFound(fmt.Sprintf("未能获取商户列表,%s", err.Error()))
}
var tenementsResponse []*vo.SimplifiedTenementResponse
copier.Copy(&tenementsResponse, &tenements)
return result.Success(
"已经获取到要查询的商户。",
fiber.Map{
"tenements": tenementsResponse,
},
)
}
// 获取指定园区中指定商户的详细信息
func getTenementDetail(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
if pass, err := checkParkBelongs(parkId, tenementLog, c, &result); !pass {
return err
}
tenementId := c.Params("tid")
if len(tenementId) == 0 {
tenementLog.Error("获取指定园区中指定商户的详细信息失败,未指定商户。")
return result.BadRequest("未指定商户。")
}
tenementLog.Info("获取指定园区中指定商户的详细信息。", zap.String("Park", parkId), zap.String("Tenement", tenementId))
tenement, err := repository.TenementRepository.RetrieveTenementDetail(parkId, tenementId)
if err != nil {
tenementLog.Error("获取指定园区中指定商户的详细信息失败,未能获取商户信息", zap.Error(err))
return result.NotFound(fmt.Sprintf("未能获取商户信息,%s", err.Error()))
}
var detail vo.TenementDetailResponse
copier.Copy(&detail, &tenement)
return result.Success(
"已经获取到要查询的商户。",
fiber.Map{
"tenement": detail,
},
)
}

142
controller/top_up.go Normal file
View File

@@ -0,0 +1,142 @@
package controller
import (
"electricity_bill_calc/logger"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/tools"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
"go.uber.org/zap"
)
var topUpLog = logger.Named("Controller", "TopUp")
func InitializeTopUpHandlers(router *fiber.App) {
router.Get("/topup/:pid", security.EnterpriseAuthorize, listTopUps)
router.Post("/topup/:pid", security.EnterpriseAuthorize, createTopUp)
router.Get("/topup/:pid/:code", security.EnterpriseAuthorize, getTopUp)
router.Delete("/topup/:pid/:code", security.EnterpriseAuthorize, deleteTopUp)
}
// 查询符合条件的商户充值记录
func listTopUps(c *fiber.Ctx) error {
result := response.NewResult(c)
park := tools.EmptyToNil(c.Params("pid"))
if park == nil {
topUpLog.Error("查询符合条件的商户充值记录,未指定要访问的园区")
return result.BadRequest("未指定要访问的园区")
}
if pass, err := checkParkBelongs(*park, topUpLog, c, &result); !pass {
return err
}
keyword := tools.EmptyToNil(c.Query("keyword"))
startDate, err := types.ParseDatep(c.Query("start_date"))
if err != nil {
topUpLog.Error("查询符合条件的商户充值记录,查询起始日期格式错误", zap.Error(err))
return result.BadRequest("查询起始日期格式错误")
}
endDate, err := types.ParseDatep(c.Query("end_date"))
if err != nil {
topUpLog.Error("查询符合条件的商户充值记录,查询结束日期格式错误", zap.Error(err))
return result.BadRequest("查询结束日期格式错误")
}
page := c.QueryInt("page", 1)
topUps, total, err := repository.TopUpRepository.ListTopUps(*park, startDate, endDate, keyword, uint(page))
if err != nil {
topUpLog.Error("查询符合条件的商户充值记录,查询失败", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "商户充值记录查询不成功")
}
topUpLog.Debug("检查获取到的数据", zap.Any("topUps", topUps), zap.Int64("total", total))
topUpDetails := make([]*vo.TopUpDetailQueryResponse, 0)
copier.Copy(&topUpDetails, &topUps)
topUpLog.Debug("检查转换后的数据", zap.Any("topUpDetails", topUpDetails))
return result.Success(
"已经获取到符合条件的商户充值记录",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"topUps": topUpDetails},
)
}
// 获取指定充值记录的详细内容
func getTopUp(c *fiber.Ctx) error {
result := response.NewResult(c)
park := tools.EmptyToNil(c.Params("pid"))
if park == nil {
topUpLog.Error("获取指定充值记录的详细内容,未指定要访问的园区")
return result.BadRequest("未指定要访问的园区")
}
if pass, err := checkParkBelongs(*park, topUpLog, c, &result); !pass {
return err
}
topUpCode := tools.EmptyToNil(c.Params("code"))
if topUpCode == nil {
topUpLog.Error("获取指定充值记录的详细内容,未指定要查询的充值记录")
return result.BadRequest("未指定要查询的充值记录")
}
topUp, err := repository.TopUpRepository.GetTopUp(*park, *topUpCode)
if err != nil {
topUpLog.Error("获取指定充值记录的详细内容,查询失败", zap.Error(err))
return result.NotFound("未找到指定的商户充值记录")
}
var topUpDetail vo.TopUpDetailQueryResponse
copier.Copy(&topUpDetail, &topUp)
return result.Success(
"已经获取到指定充值记录的详细内容",
fiber.Map{"topup": topUpDetail},
)
}
// 创建一条新的商户充值记录
func createTopUp(c *fiber.Ctx) error {
result := response.NewResult(c)
park := tools.EmptyToNil(c.Params("pid"))
if park == nil {
topUpLog.Error("创建一条新的商户充值记录,未指定要访问的园区")
return result.BadRequest("未指定要访问的园区")
}
if pass, err := checkParkBelongs(*park, topUpLog, c, &result); !pass {
return err
}
var form vo.TopUpCreationForm
if err := c.BodyParser(&form); err != nil {
topUpLog.Error("创建一条新的商户充值记录,请求体解析失败", zap.Error(err))
return result.BadRequest("请求体解析失败")
}
if err := repository.TopUpRepository.CreateTopUp(*park, &form); err != nil {
topUpLog.Error("创建一条新的商户充值记录,创建失败", zap.Error(err))
return result.NotAccept("商户充值记录创建不成功")
}
return result.Created(
"已经创建一条新的商户充值记录",
)
}
// 删除一条指定的商户充值记录
func deleteTopUp(c *fiber.Ctx) error {
result := response.NewResult(c)
park := tools.EmptyToNil(c.Params("pid"))
if park == nil {
topUpLog.Error("删除一条指定的商户充值记录,未指定要访问的园区")
return result.BadRequest("未指定要访问的园区")
}
if pass, err := checkParkBelongs(*park, topUpLog, c, &result); !pass {
return err
}
topUpCode := tools.EmptyToNil(c.Params("code"))
if topUpCode == nil {
topUpLog.Error("删除一条指定的商户充值记录,未指定要删除的充值记录")
return result.BadRequest("未指定要删除的充值记录")
}
if err := repository.TopUpRepository.DeleteTopUp(*park, *topUpCode); err != nil {
topUpLog.Error("删除一条指定的商户充值记录,删除失败", zap.Error(err))
return result.NotAccept("商户充值记录删除不成功")
}
return result.Deleted(
"已经删除一条指定的商户充值记录",
)
}

View File

@@ -3,51 +3,56 @@ package controller
import (
"electricity_bill_calc/cache"
"electricity_bill_calc/exceptions"
"electricity_bill_calc/global"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"electricity_bill_calc/tools"
"fmt"
"electricity_bill_calc/vo"
"net/http"
"strconv"
"github.com/gofiber/fiber/v2"
"github.com/shopspring/decimal"
"go.uber.org/zap"
)
func InitializeUserController(router *fiber.App) {
router.Delete("/password/:uid", security.OPSAuthorize, invalidUserPassword)
router.Delete("/login", security.MustAuthenticated, logout)
router.Put("/password", resetUserPassword)
router.Get("/accounts", security.ManagementAuthorize, listPagedUser)
router.Post("/login", login)
router.Put("/account/enabled/state", security.OPSAuthorize, switchUserEnabling)
router.Post("/account", security.OPSAuthorize, createOPSAndManagementAccount)
router.Get("/account/:uid", security.MustAuthenticated, getUserDetail)
var userLog = logger.Named("Handler", "User")
func InitializeUserHandlers(router *fiber.App) {
router.Delete("/login", security.MustAuthenticated, doLogout)
router.Post("/login", doLogin)
router.Get("/account", security.OPSAuthorize, searchUsers)
router.Post("/account", security.OPSAuthorize, createOPSAccount)
router.Get("/account/:uid", security.MustAuthenticated, fetchUserInformation)
router.Put("/account/:uid", security.OPSAuthorize, modifyUserInformation)
router.Put("/account/enabled/state", security.OPSAuthorize, changeUserState)
router.Get("/expiration", security.EnterpriseAuthorize, getAccountExpiration)
router.Post("/enterprise", security.OPSAuthorize, createEnterpriseAccount)
router.Put("/account/:uid", security.OPSAuthorize, modifyAccountDetail)
router.Get("/enterprise/quick/search", security.OPSAuthorize, quickSearchEnterprise)
router.Get("/expiration", security.EnterpriseAuthorize, fetchExpiration)
router.Put("/password", resetUserPassword)
router.Delete("/password/:uid", security.OPSAuthorize, invalidUserPassword)
}
type _LoginFormData struct {
type _LoginForm struct {
Username string `json:"uname"`
Password string `json:"upass"`
Type int8 `json:"type"`
Type int16 `json:"type"`
}
func login(c *fiber.Ctx) error {
func doLogin(c *fiber.Ctx) error {
result := response.NewResult(c)
loginData := new(_LoginFormData)
loginData := new(_LoginForm)
if err := c.BodyParser(loginData); err != nil {
userLog.Error("表单解析失败!", zap.Error(err))
return result.Error(http.StatusInternalServerError, "表单解析失败。")
}
var (
session *model.Session
err error
)
userLog.Info("有用户请求登录。", zap.String("username", loginData.Username), zap.Int16("type", loginData.Type))
if loginData.Type == model.USER_TYPE_ENT {
session, err = service.UserService.ProcessEnterpriseUserLogin(loginData.Username, loginData.Password)
} else {
@@ -60,74 +65,28 @@ func login(c *fiber.Ctx) error {
}
return result.Error(int(authError.Code), authError.Message)
} else {
userLog.Error("用户登录请求处理失败!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
}
return result.LoginSuccess(session)
}
func logout(c *fiber.Ctx) error {
func doLogout(c *fiber.Ctx) error {
result := response.NewResult(c)
session := c.Locals("session")
if session == nil {
session, err := _retreiveSession(c)
if err != nil {
return result.Success("用户会话已结束。")
}
_, err := cache.ClearSession(session.(*model.Session).Token)
_, err = cache.ClearSession(session.Token)
if err != nil {
userLog.Error("用户登出处理失败!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success("用户已成功登出系统。")
}
func invalidUserPassword(c *fiber.Ctx) error {
result := response.NewResult(c)
targetUserId := c.Params("uid")
verifyCode, err := service.UserService.InvalidUserPassword(targetUserId)
if _, ok := err.(exceptions.NotFoundError); ok {
return result.NotFound("未找到指定用户。")
}
if _, ok := err.(exceptions.UnsuccessfulOperationError); ok {
return result.NotAccept("未能成功更新用户的密码。")
}
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Json(http.StatusAccepted, "用户密码已经失效", fiber.Map{"verify": verifyCode})
}
type _ResetPasswordFormData struct {
VerifyCode string `json:"verifyCode"`
Username string `json:"uname"`
NewPassword string `json:"newPass"`
}
func resetUserPassword(c *fiber.Ctx) error {
result := response.NewResult(c)
resetForm := new(_ResetPasswordFormData)
if err := c.BodyParser(resetForm); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
verified, err := service.UserService.VerifyUserPassword(resetForm.Username, resetForm.VerifyCode)
if _, ok := err.(exceptions.NotFoundError); ok {
return result.NotFound("指定的用户不存在。")
}
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
if !verified {
return result.Error(http.StatusUnauthorized, "验证码不正确。")
}
completed, err := service.UserService.ResetUserPassword(resetForm.Username, resetForm.NewPassword)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
if completed {
return result.Updated("用户凭据已更新。")
}
return result.NotAccept("用户凭据未能成功更新。")
}
func listPagedUser(c *fiber.Ctx) error {
func searchUsers(c *fiber.Ctx) error {
result := response.NewResult(c)
requestPage, err := strconv.Atoi(c.Query("page", "1"))
if err != nil {
@@ -145,213 +104,230 @@ func listPagedUser(c *fiber.Ctx) error {
} else {
requestUserStat = &state
}
users, total, err := service.UserService.ListUserDetail(requestKeyword, requestUserType, requestUserStat, requestPage)
users, total, err := repository.UserRepository.FindUser(
&requestKeyword,
int16(requestUserType),
requestUserStat,
uint(requestPage),
)
if err != nil {
return result.NotFound(err.Error())
}
return result.Json(
http.StatusOK,
return result.Success(
"已取得符合条件的用户集合。",
response.NewPagedResponse(requestPage, total).ToMap(),
fiber.Map{"accounts": users},
)
}
type _UserStateChangeFormData struct {
UserID string `json:"uid" form:"uid"`
Enabled bool `json:"enabled" form:"enabled"`
}
func switchUserEnabling(c *fiber.Ctx) error {
result := response.NewResult(c)
switchForm := new(_UserStateChangeFormData)
if err := c.BodyParser(switchForm); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
err := service.UserService.SwitchUserState(switchForm.UserID, switchForm.Enabled)
if err != nil {
if nfErr, ok := err.(*exceptions.NotFoundError); ok {
return result.NotFound(nfErr.Message)
} else {
return result.Error(http.StatusInternalServerError, err.Error())
}
}
return result.Updated("用户状态已经更新。")
}
type _OPSAccountCreationFormData struct {
Username string `json:"username" form:"username"`
Name string `json:"name" form:"name"`
Contact *string `json:"contact" form:"contact"`
Phone *string `json:"phone" form:"phone"`
Type int `json:"type" form:"type"`
}
func createOPSAndManagementAccount(c *fiber.Ctx) error {
result := response.NewResult(c)
creationForm := new(_OPSAccountCreationFormData)
if err := c.BodyParser(creationForm); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
exists, err := service.UserService.IsUsernameExists(creationForm.Username)
if exists {
return result.Conflict("指定的用户名已经被使用了。")
}
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
newUser := new(model.User)
newUser.Username = creationForm.Username
newUser.Type = int8(creationForm.Type)
newUser.Enabled = true
newUserDetail := new(model.UserDetail)
newUserDetail.Name = &creationForm.Name
newUserDetail.Contact = creationForm.Contact
newUserDetail.Phone = creationForm.Phone
newUserDetail.UnitServiceFee = decimal.Zero
newUserDetail.ServiceExpiration, _ = model.ParseDate("2099-12-31")
verifyCode, err := service.UserService.CreateUser(newUser, newUserDetail)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
cache.AbolishRelation("user")
return result.Json(http.StatusCreated, "用户已经成功创建。", fiber.Map{"verify": verifyCode})
}
func getUserDetail(c *fiber.Ctx) error {
result := response.NewResult(c)
targetUserId := c.Params("uid")
exists, err := service.UserService.IsUserExists(targetUserId)
if !exists {
return result.NotFound("指定的用户不存在。")
}
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
userDetail, err := service.UserService.FetchUserDetail(targetUserId)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Json(http.StatusOK, "用户详细信息已获取到。", fiber.Map{"user": userDetail})
}
type _EnterpriseCreationFormData struct {
Username string `json:"username" form:"username"`
Name string `json:"name" form:"name"`
Region *string `json:"region" form:"region"`
Address *string `json:"address" form:"address"`
Contact *string `json:"contact" form:"contact"`
Phone *string `json:"phone" form:"phone"`
UnitServiceFee *string `json:"unitServiceFee" form:"unitServiceFee"`
}
func createEnterpriseAccount(c *fiber.Ctx) error {
result := response.NewResult(c)
creationForm := new(_EnterpriseCreationFormData)
if err := c.BodyParser(creationForm); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
exists, err := service.UserService.IsUsernameExists(creationForm.Username)
if exists {
return result.Conflict("指定的用户名已经被使用了。")
}
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
newUser := new(model.User)
newUser.Username = creationForm.Username
newUser.Type = model.USER_TYPE_ENT
newUser.Enabled = true
newUserDetail := new(model.UserDetail)
newUserDetail.Name = &creationForm.Name
newUserDetail.Contact = creationForm.Contact
newUserDetail.Phone = creationForm.Phone
newUserDetail.UnitServiceFee, err = decimal.NewFromString(*creationForm.UnitServiceFee)
if err != nil {
return result.BadRequest("用户月服务费无法解析。")
}
newUserDetail.ServiceExpiration = model.NewEmptyDate()
verifyCode, err := service.UserService.CreateUser(newUser, newUserDetail)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
cache.AbolishRelation("user")
return result.Json(http.StatusCreated, "用户已经成功创建。", fiber.Map{"verify": verifyCode})
}
type _AccountModificationFormData struct {
Name string `json:"name" form:"name"`
Region *string `json:"region" form:"region"`
Address *string `json:"address" form:"address"`
Contact *string `json:"contact" form:"contact"`
Phone *string `json:"phone" form:"phone"`
UnitServiceFee *string `json:"unitServiceFee" form:"unitServiceFee"`
}
func modifyAccountDetail(c *fiber.Ctx) error {
result := response.NewResult(c)
targetUserId := c.Params("uid")
modForm := new(_AccountModificationFormData)
if err := c.BodyParser(modForm); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
exists, err := service.UserService.IsUserExists(targetUserId)
if !exists {
return result.NotFound("指定的用户不存在。")
}
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
newUserInfo := new(model.UserDetail)
newUserInfo.Id = targetUserId
newUserInfo.Name = &modForm.Name
if len(modForm.Name) > 0 {
abbr := tools.PinyinAbbr(modForm.Name)
newUserInfo.Abbr = &abbr
}
newUserInfo.Region = modForm.Region
newUserInfo.Address = modForm.Address
newUserInfo.Contact = modForm.Contact
newUserInfo.Phone = modForm.Phone
newUserInfo.UnitServiceFee, err = decimal.NewFromString(*modForm.UnitServiceFee)
if err != nil {
return result.BadRequest("用户月服务费无法解析。")
}
_, err = global.DB.NewUpdate().Model(newUserInfo).
WherePK().
Column("name", "abbr", "region", "address", "contact", "phone", "unit_service_fee").
Exec(c.Context())
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
cache.AbolishRelation(fmt.Sprintf("user:%s", targetUserId))
return result.Updated("指定用户的信息已经更新。")
}
func quickSearchEnterprise(c *fiber.Ctx) error {
result := response.NewResult(c)
keyword := c.Query("keyword")
searchResult, err := service.UserService.SearchLimitUsers(keyword, 6)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Json(http.StatusOK, "已查询到存在符合条件的企业", fiber.Map{"users": searchResult})
}
func fetchExpiration(c *fiber.Ctx) error {
func getAccountExpiration(c *fiber.Ctx) error {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
return result.Unauthorized(err.Error())
userLog.Error("未找到有效的用户会话。", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
user, err := service.UserService.FetchUserDetail(session.Uid)
userDetail, err := repository.UserRepository.FindUserDetailById(session.Uid)
if err != nil {
return result.NotFound(err.Error())
return result.NotFound("未找到指定的用户档案")
}
return result.Json(
http.StatusOK,
return result.Success(
"已经取得用户的服务期限信息",
fiber.Map{"expiration": user.ServiceExpiration.Format("2006-01-02")},
fiber.Map{"expiration": userDetail.ServiceExpiration.Format("2006-01-02")},
)
}
func createOPSAccount(c *fiber.Ctx) error {
userLog.Info("请求创建运维或监管账户。")
result := response.NewResult(c)
creationForm := new(vo.MGTAndOPSAccountCreationForm)
if err := c.BodyParser(creationForm); err != nil {
userLog.Error("表单解析失败!", zap.Error(err))
return result.UnableToParse("无法解析提交的数据。")
}
exists, err := repository.UserRepository.IsUsernameExists(creationForm.Username)
if err != nil {
userLog.Error("检查用户名是否已经被使用时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if exists {
return result.Conflict("指定的用户名已经被使用了。")
}
verifyCode, err := service.UserService.CreateUserAccount(creationForm.IntoUser(), creationForm.IntoUserDetail())
if err != nil {
userLog.Error("创建用户账户时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Created("用户已经成功创建。", fiber.Map{"verify": verifyCode})
}
func fetchUserInformation(c *fiber.Ctx) error {
userLog.Info("请求获取用户详细信息。")
result := response.NewResult(c)
targetUserId := c.Params("uid")
exists, err := repository.UserRepository.IsUserExists(targetUserId)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
if !exists {
return result.NotFound("指定的用户不存在。")
}
userDetail, err := repository.UserRepository.FindUserDetailById(targetUserId)
if err != nil {
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success("用户详细信息已获取到。", fiber.Map{"user": userDetail})
}
func modifyUserInformation(c *fiber.Ctx) error {
userLog.Info("请求修改用户详细信息。")
session, _ := _retreiveSession(c)
result := response.NewResult(c)
targetUserId := c.Params("uid")
exists, err := repository.UserRepository.IsUserExists(targetUserId)
if err != nil {
userLog.Error("检查用户是否存在时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !exists {
return result.NotFound("指定的用户不存在。")
}
modificationForm := new(vo.UserDetailModificationForm)
if err := c.BodyParser(modificationForm); err != nil {
userLog.Error("表单解析失败!", zap.Error(err))
return result.UnableToParse("无法解析提交的数据。")
}
userLog.Debug("用户服务费修改表单:", zap.Any("form", modificationForm))
detailFormForUpdate, err := modificationForm.IntoModificationModel()
if err != nil {
userLog.Error("用户服务费解析转换失败!", zap.Error(err))
return result.UnableToParse("无法解析提交的数据,服务费格式不正确。")
}
if ok, err := repository.UserRepository.UpdateDetail(targetUserId, *detailFormForUpdate, &session.Uid); err != nil || !ok {
userLog.Error("更新用户详细信息失败!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Updated("指定用户的信息已经更新。")
}
func changeUserState(c *fiber.Ctx) error {
userLog.Info("请求修改用户状态。")
result := response.NewResult(c)
modificationForm := new(vo.UserStateChangeForm)
if err := c.BodyParser(modificationForm); err != nil {
userLog.Error("表单解析失败!", zap.Error(err))
return result.UnableToParse("无法解析提交的数据。")
}
exists, err := repository.UserRepository.IsUserExists(modificationForm.Uid)
if err != nil {
userLog.Error("检查用户是否存在时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !exists {
return result.NotFound("指定的用户不存在。")
}
if ok, err := repository.UserRepository.ChangeState(modificationForm.Uid, modificationForm.Enabled); err != nil || !ok {
userLog.Error("更新用户状态失败!", zap.Error(err))
return result.NotAccept("无法更新用户状态。")
}
return result.Updated("用户的状态已经更新。")
}
func createEnterpriseAccount(c *fiber.Ctx) error {
userLog.Info("请求创建企业账户。")
result := response.NewResult(c)
creationForm := new(vo.EnterpriseAccountCreationForm)
if err := c.BodyParser(creationForm); err != nil {
userLog.Error("表单解析失败!", zap.Error(err))
return result.UnableToParse("无法解析提交的数据。")
}
exists, err := repository.UserRepository.IsUsernameExists(creationForm.Username)
if err != nil {
userLog.Error("检查用户名是否已经被使用时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if exists {
return result.Conflict("指定的用户名已经被使用了。")
}
userDetail, err := creationForm.IntoUserDetail()
if err != nil {
userLog.Error("转换用户详细档案时发生错误!", zap.Error(err))
return result.UnableToParse("无法解析提交的数据,服务费格式不正确。")
}
verifyCode, err := service.UserService.CreateUserAccount(creationForm.IntoUser(), userDetail)
if err != nil {
userLog.Error("创建用户账户时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Created("用户已经成功创建。", fiber.Map{"verify": verifyCode})
}
func quickSearchEnterprise(c *fiber.Ctx) error {
userLog.Info("请求快速查询企业账户。")
result := response.NewResult(c)
keyword := c.Query("keyword")
limit := c.QueryInt("limit", 6)
if limit < 1 {
limit = 6
}
users, err := repository.UserRepository.SearchUsersWithLimit(nil, &keyword, uint(limit))
if err != nil {
userLog.Error("查询用户时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Success("已查询到存在符合条件的企业", fiber.Map{"users": users})
}
func resetUserPassword(c *fiber.Ctx) error {
userLog.Info("请求重置用户密码。")
result := response.NewResult(c)
repasswordForm := new(vo.RepasswordForm)
if err := c.BodyParser(repasswordForm); err != nil {
userLog.Error("表单解析失败!", zap.Error(err))
return result.UnableToParse("无法解析提交的数据。")
}
user, err := repository.UserRepository.FindUserByUsername(repasswordForm.Username)
if err != nil {
userLog.Error("检查用户是否存在时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if user == nil {
return result.NotFound("指定的用户不存在。")
}
if !service.UserService.MatchUserPassword(user.Password, repasswordForm.VerifyCode) {
return result.Unauthorized("验证码不正确。")
}
ok, err := repository.UserRepository.UpdatePassword(user.Id, repasswordForm.NewPassword, false)
if err != nil {
userLog.Error("更新用户凭据时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !ok {
return result.NotAccept("无法更新用户凭据。")
}
return result.Updated("用户凭据已经更新。")
}
func invalidUserPassword(c *fiber.Ctx) error {
userLog.Info("请求使用户凭据失效。")
result := response.NewResult(c)
uid := c.Params("uid")
exists, err := repository.UserRepository.IsUserExists(uid)
if err != nil {
userLog.Error("检查用户是否存在时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !exists {
return result.NotFound("指定的用户不存在。")
}
verifyCode := tools.RandStr(10)
ok, err := repository.UserRepository.UpdatePassword(uid, verifyCode, true)
if err != nil {
userLog.Error("更新用户凭据时发生错误!", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
if !ok {
return result.NotAccept("未能更新用户凭据。")
}
return result.Updated("用户凭据已经更新。", fiber.Map{"verify": verifyCode})
}

View File

@@ -1,81 +1,19 @@
package controller
import (
"electricity_bill_calc/exceptions"
"electricity_bill_calc/response"
"electricity_bill_calc/logger"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"net/http"
"strconv"
"github.com/gofiber/fiber/v2"
)
func InitializeWithdrawController(router *fiber.App) {
router.Delete("/publicity/:pid", security.EnterpriseAuthorize, applyReportWithdraw)
router.Get("/withdraws", security.OPSAuthorize, fetchWithdrawsWaitingAutdit)
router.Put("/withdraw/:rid", security.OPSAuthorize, auditWithdraw)
}
var withdrawLog = logger.Named("Handler", "Report")
func applyReportWithdraw(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("pid")
if ensure, err := ensureReportBelongs(c, &result, requestReportId); !ensure {
return err
}
deleted, err := service.WithdrawService.ApplyWithdraw(requestReportId)
if err != nil {
if nfErr, ok := err.(exceptions.NotFoundError); ok {
return result.NotFound(nfErr.Error())
} else if ioErr, ok := err.(exceptions.ImproperOperateError); ok {
return result.NotAccept(ioErr.Error())
} else {
return result.Error(http.StatusInternalServerError, err.Error())
}
}
if !deleted {
return result.Error(http.StatusInternalServerError, "未能完成公示报表的申请撤回操作。")
}
return result.Success("指定的公示报表已经申请撤回。")
func InitializewithdrawHandlers(router *fiber.App) {
router.Put("/withdraw/:rid", security.EnterpriseAuthorize, changeReportWithdraw)
}
func changeReportWithdraw(ctx *fiber.Ctx) error {
//result := response.NewResult(ctx)
//reportId := ctx.Params("rid")
return nil
func fetchWithdrawsWaitingAutdit(c *fiber.Ctx) error {
result := response.NewResult(c)
keyword := c.Query("keyword")
requestPage, err := strconv.Atoi(c.Query("page", "1"))
if err != nil {
return result.NotAccept("查询参数[page]格式不正确。")
}
reports, totalitems, err := service.WithdrawService.FetchPagedWithdrawApplies(requestPage, keyword)
if err != nil {
return result.NotFound(err.Error())
}
return result.Json(
http.StatusOK,
"已经取得符合条件的等待审核的撤回申请。",
response.NewPagedResponse(requestPage, totalitems).ToMap(),
fiber.Map{"records": reports},
)
}
type WithdrawAuditFormData struct {
Audit bool `json:"audit" form:"audit"`
}
func auditWithdraw(c *fiber.Ctx) error {
result := response.NewResult(c)
requestReportId := c.Params("rid")
formData := new(WithdrawAuditFormData)
if err := c.BodyParser(formData); err != nil {
return result.UnableToParse("无法解析提交的数据。")
}
err := service.WithdrawService.AuditWithdraw(requestReportId, formData.Audit)
if err != nil {
if nfErr, ok := err.(exceptions.NotFoundError); ok {
return result.NotFound(nfErr.Error())
} else {
return result.NotAccept(err.Error())
}
}
return result.Success("指定公示报表的撤回申请已经完成审核")
}