zk 2 năm trước cách đây
mục cha
commit
ebb898cf19
39 tập tin đã thay đổi với 17032 bổ sung622 xóa
  1. 2 0
      server/api/v1/autocode/enter.go
  2. 61 1
      server/api/v1/autocode/problem_info.go
  3. 142 0
      server/api/v1/autocode/read_count.go
  4. 2 0
      server/api/v1/system/enter.go
  5. 18 8
      server/api/v1/system/sys_user.go
  6. 82 0
      server/api/v1/system/wechat.go
  7. 6 4
      server/config.yaml
  8. 2 0
      server/config/wxxcx.go
  9. 2 0
      server/core/server.go
  10. 2 0
      server/global/global.go
  11. 2 0
      server/go.mod
  12. 1 0
      server/initialize/gorm.go
  13. 3 0
      server/initialize/router.go
  14. 33 0
      server/initialize/wechat.go
  15. 23 15
      server/model/autocode/problem_info.go
  16. 21 0
      server/model/autocode/read_count.go
  17. 11 0
      server/model/autocode/request/ReadCountSearch.go
  18. 6 0
      server/model/autocode/request/sendUser.go
  19. 11 0
      server/model/request/read_count.go
  20. 1 0
      server/model/system/request/sys_user.go
  21. 3 1
      server/model/system/sys_user.go
  22. 2 0
      server/router/autocode/enter.go
  23. 2 0
      server/router/autocode/problem_info.go
  24. 24 0
      server/router/autocode/read_count.go
  25. 1 0
      server/router/system/enter.go
  26. 17 0
      server/router/system/wechat.go
  27. 2 0
      server/service/autocode/enter.go
  28. 6 0
      server/service/autocode/problem_info.go
  29. 71 0
      server/service/autocode/read_count.go
  30. 1 0
      server/service/system/enter.go
  31. 13 1
      server/service/system/sys_user.go
  32. 9 0
      server/service/system/wechat.go
  33. 15536 1
      web/package-lock.json
  34. 17 0
      web/src/api/problemInfo.js
  35. 97 0
      web/src/api/unit.js
  36. 91 3
      web/src/view/problemInfo/problemInfo.vue
  37. 205 0
      web/src/view/unit/unit.vue
  38. 78 0
      web/src/view/unit/unitForm.vue
  39. 426 588
      web/yarn.lock

+ 2 - 0
server/api/v1/autocode/enter.go

@@ -6,5 +6,7 @@ type ApiGroup struct {
 	ContentApi
 	PlaceApi
 	ProblemInfoApi
+	ReadCountApi
+	UnitApi
 	// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
 }

+ 61 - 1
server/api/v1/autocode/problem_info.go

@@ -1,7 +1,7 @@
 package autocode
 
 import (
-	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	global "github.com/flipped-aurora/gin-vue-admin/server/global"
 	"github.com/flipped-aurora/gin-vue-admin/server/model/autocode"
 	autocodeReq "github.com/flipped-aurora/gin-vue-admin/server/model/autocode/request"
 	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
@@ -9,6 +9,7 @@ import (
 	"github.com/flipped-aurora/gin-vue-admin/server/service"
 	"github.com/flipped-aurora/gin-vue-admin/server/utils"
 	"github.com/gin-gonic/gin"
+	"github.com/silenceper/wechat/v2/officialaccount/message"
 	"go.uber.org/zap"
 	"strconv"
 	"time"
@@ -71,6 +72,41 @@ func (problemInfoApi *ProblemInfoApi) ExportExcel(c *gin.Context) {
 	}
 }
 
+func (problemInfoApi *ProblemInfoApi) SendUser(c *gin.Context) {
+	var sendUser autocodeReq.SendUser
+	_ = c.ShouldBindJSON(&sendUser)
+	_, problem := problemInfoService.GetProblemInfo(sendUser.ProblemID)
+	_, oper := service.ServiceGroupApp.SystemServiceGroup.FindUserById(int(problem.Oper))
+	appid := global.GVA_CONFIG.Wxxcx.Appid
+	for _, id := range sendUser.ID {
+		userId, _ := strconv.Atoi(id)
+		_, user := service.ServiceGroupApp.SystemServiceGroup.FindUserById(userId)
+		if user.WechatId == "" {
+			continue
+		}
+		msg := &message.TemplateMessage{
+			ToUser:     user.WechatId,
+			TemplateID: "DAyIWY0UUaqGxMG13MUtNCkNFKEe719sp75P0tT7FS4",
+			Data: map[string]*message.TemplateDataItem{
+				"first":    {Value: "有新的站点问题"},
+				"keyword1": {Value: oper.Username},
+				"keyword2": {Value: problem.SiteName},
+				"keyword3": {Value: problem.Department},
+				"keyword4": {Value: problem.CreatedAt.Format("2006-01-02 15:04:05")},
+				"remark":   {Value: "点击查看问题"},
+			},
+			MiniProgram: struct {
+				AppID    string `json:"appid"`
+				PagePath string `json:"pagepath"`
+			}{AppID: appid, PagePath: "/pages/public-details?id=" + strconv.Itoa(int(sendUser.ProblemID))},
+		}
+		if _, err := global.GVA_WECHAT.GetTemplate().Send(msg); err != nil {
+			global.GVA_LOG.Error("微信模板通知失败!", zap.Any("err", err))
+		}
+	}
+	response.OkWithMessage("发送成功", c)
+}
+
 // DeleteProblemInfo 删除ProblemInfo
 // @Tags ProblemInfo
 // @Summary 删除ProblemInfo
@@ -158,6 +194,30 @@ func (problemInfoApi *ProblemInfoApi) FindProblemInfo(c *gin.Context) {
 	}
 }
 
+func (problemInfoApi *ProblemInfoApi) FindProblemPInfo(c *gin.Context) {
+	var problemInfo autocode.ProblemInfo
+	_ = c.ShouldBindQuery(&problemInfo)
+	if err, reproblemInfo := problemInfoService.GetProblemInfo(problemInfo.ID); err != nil {
+		global.GVA_LOG.Error("查询失败!", zap.Any("err", err))
+		response.FailWithMessage("查询失败", c)
+	} else {
+		userId := utils.GetUserID(c)
+		//记录查看记录
+		if err, readCount := service.ServiceGroupApp.AutoCodeServiceGroup.ReadCountService.GetReadCountByUserId(int(userId), int(problemInfo.ID)); err != nil {
+			//新增
+			service.ServiceGroupApp.AutoCodeServiceGroup.ReadCountService.CreateReadCount(autocode.ReadCount{ProblemId: problemInfo.ID, UserId: userId, UserName: utils.GetUserInfo(c).Username})
+		} else {
+			service.ServiceGroupApp.AutoCodeServiceGroup.ReadCountService.UpdateReadCountBy(readCount.ID)
+		}
+
+		//累加总阅读量
+		problemInfoService.UpdateProblemInfoCount(problemInfo.ID)
+		//param := reqMode.SysDictionarySearch{, request.PageInfo{PageSize: 9999, Page: 0}}
+		_, reproblemInfo.MatterList = service.ServiceGroupApp.SystemServiceGroup.DictionaryService.GetSysDictionaryDetail(reproblemInfo.SiteType)
+		response.OkWithData(gin.H{"reproblemInfo": reproblemInfo}, c)
+	}
+}
+
 // GetProblemInfoList 分页获取ProblemInfo列表
 // @Tags ProblemInfo
 // @Summary 分页获取ProblemInfo列表

+ 142 - 0
server/api/v1/autocode/read_count.go

@@ -0,0 +1,142 @@
+package autocode
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/autocode"
+	autocodeReq "github.com/flipped-aurora/gin-vue-admin/server/model/autocode/request"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
+	"github.com/flipped-aurora/gin-vue-admin/server/service"
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+)
+
+type ReadCountApi struct {
+}
+
+var readCountService = service.ServiceGroupApp.AutoCodeServiceGroup.ReadCountService
+
+// CreateReadCount 创建ReadCount
+// @Tags ReadCount
+// @Summary 创建ReadCount
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body autocode.ReadCount true "创建ReadCount"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
+// @Router /readCount/createReadCount [post]
+func (readCountApi *ReadCountApi) CreateReadCount(c *gin.Context) {
+	var readCount autocode.ReadCount
+	_ = c.ShouldBindJSON(&readCount)
+	if err := readCountService.CreateReadCount(readCount); err != nil {
+		global.GVA_LOG.Error("创建失败!", zap.Any("err", err))
+		response.FailWithMessage("创建失败", c)
+	} else {
+		response.OkWithMessage("创建成功", c)
+	}
+}
+
+// DeleteReadCount 删除ReadCount
+// @Tags ReadCount
+// @Summary 删除ReadCount
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body autocode.ReadCount true "删除ReadCount"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
+// @Router /readCount/deleteReadCount [delete]
+func (readCountApi *ReadCountApi) DeleteReadCount(c *gin.Context) {
+	var readCount autocode.ReadCount
+	_ = c.ShouldBindJSON(&readCount)
+	if err := readCountService.DeleteReadCount(readCount); err != nil {
+		global.GVA_LOG.Error("删除失败!", zap.Any("err", err))
+		response.FailWithMessage("删除失败", c)
+	} else {
+		response.OkWithMessage("删除成功", c)
+	}
+}
+
+// DeleteReadCountByIds 批量删除ReadCount
+// @Tags ReadCount
+// @Summary 批量删除ReadCount
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body request.IdsReq true "批量删除ReadCount"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"批量删除成功"}"
+// @Router /readCount/deleteReadCountByIds [delete]
+func (readCountApi *ReadCountApi) DeleteReadCountByIds(c *gin.Context) {
+	var IDS request.IdsReq
+	_ = c.ShouldBindJSON(&IDS)
+	if err := readCountService.DeleteReadCountByIds(IDS); err != nil {
+		global.GVA_LOG.Error("批量删除失败!", zap.Any("err", err))
+		response.FailWithMessage("批量删除失败", c)
+	} else {
+		response.OkWithMessage("批量删除成功", c)
+	}
+}
+
+// UpdateReadCount 更新ReadCount
+// @Tags ReadCount
+// @Summary 更新ReadCount
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body autocode.ReadCount true "更新ReadCount"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
+// @Router /readCount/updateReadCount [put]
+func (readCountApi *ReadCountApi) UpdateReadCount(c *gin.Context) {
+	var readCount autocode.ReadCount
+	_ = c.ShouldBindJSON(&readCount)
+	if err := readCountService.UpdateReadCount(readCount); err != nil {
+		global.GVA_LOG.Error("更新失败!", zap.Any("err", err))
+		response.FailWithMessage("更新失败", c)
+	} else {
+		response.OkWithMessage("更新成功", c)
+	}
+}
+
+// FindReadCount 用id查询ReadCount
+// @Tags ReadCount
+// @Summary 用id查询ReadCount
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data query autocode.ReadCount true "用id查询ReadCount"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
+// @Router /readCount/findReadCount [get]
+func (readCountApi *ReadCountApi) FindReadCount(c *gin.Context) {
+	var readCount autocode.ReadCount
+	_ = c.ShouldBindQuery(&readCount)
+	if err, rereadCount := readCountService.GetReadCount(readCount.ID); err != nil {
+		global.GVA_LOG.Error("查询失败!", zap.Any("err", err))
+		response.FailWithMessage("查询失败", c)
+	} else {
+		response.OkWithData(gin.H{"rereadCount": rereadCount}, c)
+	}
+}
+
+// GetReadCountList 分页获取ReadCount列表
+// @Tags ReadCount
+// @Summary 分页获取ReadCount列表
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data query autocodeReq.ReadCountSearch true "分页获取ReadCount列表"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
+// @Router /readCount/getReadCountList [get]
+func (readCountApi *ReadCountApi) GetReadCountList(c *gin.Context) {
+	var pageInfo autocodeReq.ReadCountSearch
+	_ = c.ShouldBindQuery(&pageInfo)
+	if err, list, total := readCountService.GetReadCountInfoList(pageInfo); err != nil {
+		global.GVA_LOG.Error("获取失败!", zap.Any("err", err))
+		response.FailWithMessage("获取失败", c)
+	} else {
+		response.OkWithDetailed(response.PageResult{
+			List:     list,
+			Total:    total,
+			Page:     pageInfo.Page,
+			PageSize: pageInfo.PageSize,
+		}, "获取成功", c)
+	}
+}

+ 2 - 0
server/api/v1/system/enter.go

@@ -15,6 +15,7 @@ type ApiGroup struct {
 	JwtApi
 	OperationRecordApi
 	AuthorityMenuApi
+	WechatApi
 }
 
 var authorityService = service.ServiceGroupApp.SystemServiceGroup.AuthorityService
@@ -31,3 +32,4 @@ var baseMenuService = service.ServiceGroupApp.SystemServiceGroup.BaseMenuService
 var operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService
 var userService = service.ServiceGroupApp.SystemServiceGroup.UserService
 var systemConfigService = service.ServiceGroupApp.SystemServiceGroup.SystemConfigService
+var wechatService = service.ServiceGroupApp.SystemServiceGroup.WechatService

+ 18 - 8
server/api/v1/system/sys_user.go

@@ -2,7 +2,7 @@ package system
 
 import (
 	"context"
-	"github.com/medivhzhan/weapp"
+	weapp "github.com/medivhzhan/weapp/v2"
 	"strconv"
 	"time"
 
@@ -55,6 +55,7 @@ func (b *BaseApi) LoginWx(c *gin.Context) {
 		response.FailWithMessage("小程序信息获取异常", c)
 		return
 	}
+	global.GVA_LOG.Info("小程序登录", zap.Any("res", res))
 	global.GVA_REDIS.Set(context.Background(), "wxssk:"+res.OpenID, res.SessionKey, 0)
 	if err, user := userService.FindUserByOpenId(res.OpenID); err != nil {
 		response.CodeWithDetailed(1, res, "未注册", c)
@@ -75,14 +76,23 @@ func (b *BaseApi) RegisterWx(c *gin.Context) {
 		response.FailWithMessage(err.Error(), c)
 		return
 	}
-	authorityId := "100"
-	user := &system.SysUser{Username: r.Username, OpenId: r.OpenId, NickName: r.NickName, Password: utils.RandomString(10), HeaderImg: r.HeaderImg, AuthorityId: authorityId, Authorities: nil}
-	err, userReturn := userService.Register(*user)
-	if err != nil {
-		global.GVA_LOG.Error("注册失败!", zap.Any("err", err))
-		response.CodeMessage(2, "您已经申请过了,请耐心等待审核!", c)
+	if err, sysUser := userService.GetUserInfoByUnionId(r.UnionId); err != nil {
+		authorityId := "100"
+		user := &system.SysUser{Username: r.Username, OpenId: r.OpenId, NickName: r.NickName, Password: utils.RandomString(10), HeaderImg: r.HeaderImg, AuthorityId: authorityId, Authorities: nil}
+		regErr, userReturn := userService.Register(*user)
+		if regErr != nil {
+			global.GVA_LOG.Error("注册失败!", zap.Any("err", err))
+			response.CodeMessage(2, "您已经申请过了,请耐心等待审核!", c)
+		} else {
+			response.CodeWithDetailed(2, systemRes.SysUserResponse{User: userReturn}, "申请登陆成功,请等待审核", c)
+		}
 	} else {
-		response.CodeWithDetailed(2, systemRes.SysUserResponse{User: userReturn}, "申请登陆成功,请等待审核", c)
+		sysUser.OpenId = r.OpenId
+		sysUser.NickName = r.NickName
+		sysUser.Username = r.Username
+		sysUser.OpenId = r.HeaderImg
+		userService.SetUserInfo(sysUser)
+		response.CodeMessage(2, "资料已提交,请耐心等待审核!", c)
 	}
 }
 

+ 82 - 0
server/api/v1/system/wechat.go

@@ -0,0 +1,82 @@
+package system
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/system"
+	"github.com/flipped-aurora/gin-vue-admin/server/utils"
+	"github.com/gin-gonic/gin"
+	"github.com/silenceper/wechat/v2/officialaccount/message"
+	"go.uber.org/zap"
+)
+
+type WechatApi struct {
+}
+
+func (b *WechatApi) Req(c *gin.Context) {
+	// 传入request和responseWriter
+	server := global.GVA_WECHAT.GetServer(c.Request, c.Writer)
+	server.SkipValidate(true)
+	//设置接收消息的处理方法
+	server.SetMessageHandler(func(msg *message.MixMessage) *message.Reply {
+		//TODO
+		//回复消息:演示回复用户发送的消息
+		if msg.Event == message.EventSubscribe {
+			global.GVA_LOG.Info("用户关注", zap.Any("openId", msg.FromUserName), zap.Any("msg", msg))
+			if err, sysUser := userService.GetUserInfoByWechatId(string(msg.FromUserName)); err != nil {
+				if user, err := global.GVA_WECHAT.GetUser().GetUserInfo(string(msg.FromUserName)); err == nil {
+					global.GVA_LOG.Info("用户信息", zap.Any("user", user))
+					if err, sysUser := userService.GetUserInfoByUnionId(user.UnionID); err != nil {
+						//不存在则新增用户
+						authorityId := "100"
+						user := &system.SysUser{Username: user.OpenID, WechatId: user.OpenID, UnionId: user.UnionID, NickName: user.UnionID, Password: utils.RandomString(10), AuthorityId: authorityId, Authorities: nil}
+						userService.Register(*user)
+					} else {
+						//已存在小程序用户更新user 微信id到表
+						sysUser.WechatId = user.OpenID
+						userService.SetUserInfo(sysUser)
+					}
+				} else {
+					global.GVA_LOG.Info("用户信息拉取失败", zap.Any("err", err))
+				}
+			} else {
+				global.GVA_LOG.Info("用户已存在", zap.Any("err", err), zap.Any("sysUser", sysUser))
+			}
+			return nil
+		}
+		global.GVA_LOG.Info("用户消息", zap.Any("openId", msg.FromUserName), zap.Any("msg", msg))
+		text := message.NewText(msg.Content)
+		return &message.Reply{MsgType: message.MsgTypeImage, MsgData: text}
+
+		//article1 := message.NewArticle("测试图文1", "图文描述", "", "")
+		//articles := []*message.Article{article1}
+		//news := message.NewNews(articles)
+		//return &message.Reply{MsgType: message.MsgTypeNews, MsgData: news}
+
+		//voice := message.NewVoice(mediaID)
+		//return &message.Reply{MsgType: message.MsgTypeVoice, MsgData: voice}
+
+		//
+		//video := message.NewVideo(mediaID, "标题", "描述")
+		//return &message.Reply{MsgType: message.MsgTypeVideo, MsgData: video}
+
+		//music := message.NewMusic("标题", "描述", "音乐链接", "HQMusicUrl", "缩略图的媒体id")
+		//return &message.Reply{MsgType: message.MsgTypeMusic, MsgData: music}
+
+		//多客服消息转发
+		//transferCustomer := message.NewTransferCustomer("")
+		//return &message.Reply{MsgType: message.MsgTypeTransfer, MsgData: transferCustomer}
+	})
+
+	//处理消息接收以及回复
+	err := server.Serve()
+	if err != nil {
+		global.GVA_LOG.Error("Serve Error, err=%+v", zap.Any("err", err))
+		return
+	}
+	//发送回复的消息
+	err = server.Send()
+	if err != nil {
+		global.GVA_LOG.Error("Send Error, err=%+v", zap.Any("err", err))
+		return
+	}
+}

+ 6 - 4
server/config.yaml

@@ -43,11 +43,11 @@ jwt:
 local:
   path: uploads/file
 mysql:
-  path: n.zk1006.com:33306
+  path: 1.116.188.224:3306
   config: charset=utf8mb4&parseTime=True&loc=Local
   db-name: cc_info
   username: root
-  password: zk159256
+  password: 41051459cb7fb12d
   max-idle-conns: 0
   max-open-conns: 0
   log-mode: "info"
@@ -85,8 +85,10 @@ timer:
       compareField: created_at
       interval: 2160h
 wxxcx:
-  appid: wx7817c69b22676b75
-  secret: b51a8c120c461af12f516bb79ae450d7
+  appid: wx0dc3e4978f919285
+  secret: fdf155c29d4f6bfb104efdfcd9e99a52
+  wxid: wx66e0fbb5a735bcc4
+  wxkey: 6d9a776f8f7a485db4b1813be8c6891e
 zap:
   level: info
   format: json

+ 2 - 0
server/config/wxxcx.go

@@ -3,4 +3,6 @@ package config
 type Wxxcx struct {
 	Appid  string `mapstructure:"appid" json:"appid" yaml:"appid"`
 	Secret string `mapstructure:"secret" json:"secret" yaml:"secret"`
+	Wxid   string `mapstructure:"wxid" json:"wxid" yaml:"wxid"`
+	Wxkey  string `mapstructure:"wxkey" json:"wxkey" yaml:"wxkey"`
 }

+ 2 - 0
server/core/server.go

@@ -19,6 +19,8 @@ func RunWindowsServer() {
 		initialize.Redis()
 	}
 	Router := initialize.Routers()
+	//初始化微信公众号服务
+	initialize.Wechat()
 
 	Router.Static("/form-generator", "./resource/page")
 

+ 2 - 0
server/global/global.go

@@ -2,6 +2,7 @@ package global
 
 import (
 	"github.com/flipped-aurora/gin-vue-admin/server/utils/timer"
+	"github.com/silenceper/wechat/v2/officialaccount"
 	"github.com/songzhibin97/gkit/cache/local_cache"
 
 	"golang.org/x/sync/singleflight"
@@ -18,6 +19,7 @@ import (
 var (
 	GVA_DB     *gorm.DB
 	GVA_REDIS  *redis.Client
+	GVA_WECHAT *officialaccount.OfficialAccount
 	GVA_CONFIG config.Server
 	GVA_VP     *viper.Viper
 	//GVA_LOG    *oplogging.Logger

+ 2 - 0
server/go.mod

@@ -19,11 +19,13 @@ require (
 	github.com/jordan-wright/email v0.0.0-20200824153738-3f5bafa1cd84
 	github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible
 	github.com/medivhzhan/weapp v1.5.1
+	github.com/medivhzhan/weapp/v2 v2.5.0
 	github.com/mojocn/base64Captcha v1.3.1
 	github.com/qiniu/api.v7/v7 v7.4.1
 	github.com/robfig/cron/v3 v3.0.1
 	github.com/satori/go.uuid v1.2.0
 	github.com/shirou/gopsutil v3.21.1+incompatible
+	github.com/silenceper/wechat/v2 v2.1.2
 	github.com/songzhibin97/gkit v1.1.1
 	github.com/spf13/viper v1.7.0
 	github.com/swaggo/gin-swagger v1.3.0

+ 1 - 0
server/initialize/gorm.go

@@ -53,6 +53,7 @@ func MysqlTables(db *gorm.DB) {
 		system.SysAutoCodeHistory{},
 		// Code generated by github.com/flipped-aurora/gin-vue-admin/server Begin; DO NOT EDIT.
 		autocode.AutoCodeExample{},
+		autocode.Unit{},
 		// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
 	)
 	if err != nil {

+ 3 - 0
server/initialize/router.go

@@ -46,6 +46,8 @@ func Routers() *gin.Engine {
 		systemRouter.InitInitRouter(PublicGroup)           // 自动初始化相关
 		autocodeRouter.InitProblemInfoPRouter(PublicGroup) // 问题详情
 		autocodeRouter.InitContentPRouter(PublicGroup)     // 内容详情
+		systemRouter.InitWechatRouter(PublicGroup)         // 微信公众号
+		autocodeRouter.InitReadCountRouter(PublicGroup)    // 查阅次数查看
 	}
 	PrivateGroup := Router.Group("")
 	PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
@@ -70,6 +72,7 @@ func Routers() *gin.Engine {
 		autocodeRouter.InitContentRouter(PrivateGroup)
 		autocodeRouter.InitProblemInfoRouter(PrivateGroup)
 		autocodeRouter.InitPlaceRouter(PrivateGroup)
+		autocodeRouter.InitUnitRouter(PrivateGroup)
 		// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
 	}
 

+ 33 - 0
server/initialize/wechat.go

@@ -0,0 +1,33 @@
+package initialize
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	wechat "github.com/silenceper/wechat/v2"
+	"github.com/silenceper/wechat/v2/cache"
+	offConfig "github.com/silenceper/wechat/v2/officialaccount/config"
+	"go.uber.org/zap"
+)
+
+func Wechat() {
+	redisCfg := global.GVA_CONFIG.Redis
+	redisOpts := &cache.RedisOpts{
+		Host:        redisCfg.Addr,
+		Password:    redisCfg.Password,
+		Database:    redisCfg.DB,
+		MaxActive:   0,
+		MaxIdle:     5,
+		IdleTimeout: 9000,
+	}
+	redisCache := cache.NewRedis(redisOpts)
+	wc := &wechat.Wechat{}
+	wc.SetCache(redisCache)
+	wxCfg := global.GVA_CONFIG.Wxxcx
+	offCfg := &offConfig.Config{
+		AppID:          wxCfg.Wxid,
+		AppSecret:      wxCfg.Wxkey,
+		Token:          "zk1006",
+		EncodingAESKey: "wNwYix6c48AsPYlJvttcTRbcBivOvncPhBoUOI9YwSH",
+	}
+	global.GVA_LOG.Debug("offCfg=", zap.Any("offCfg", offCfg))
+	global.GVA_WECHAT = wc.GetOfficialAccount(offCfg)
+}

+ 23 - 15
server/model/autocode/problem_info.go

@@ -25,26 +25,34 @@ type ProblemInfo struct {
 	HandText   string               `json:"handText" form:"handText" gorm:"column:hand_text;comment:处理内容;type:varchar(255);"`
 	Department string               `json:"department" form:"department" gorm:"column:department;comment:责任部门;type:varchar(255);"`
 	Remark     string               `json:"remark" form:"remark" gorm:"column:remark;comment:问题备注;type:varchar(600);"`
+	Count      *int                 `json:"count" form:"count" gorm:"default:0;column:count;comment:阅读次数;type:int);"`
+	Integral   *int                 `json:"integral" form:"integral" gorm:"default:0;column:integral;comment:积分;type:int);"`
+	UnitName   *int                 `json:"unitName" form:"unitName" gorm:"default:0;column:unit_name;comment:单位名称;type:varchar(255));"`
+	UnitId     *int                 `json:"unitId" form:"unitId" gorm:"default:0;column:unit_id;comment:单位id;type:int);"`
 	MatterList system.SysDictionary `json:"matterList" gorm:"-"`
 }
 
 type ProblemInfo1 struct {
 	global.GVA_MODEL
-	Oper       uint                 `json:"oper" form:"oper" gorm:"column:oper;comment:发布人;type:bigint"`
-	Handler    *int                 `json:"handler" form:"handler" gorm:"column:handler;comment:处理人;type:bigint"`
-	Imgs       string               `json:"imgs" form:"imgs" gorm:"column:imgs;comment:关联图片;type:varchar(2000);"`
-	Video      string               `json:"video" form:"video" gorm:"column:video;comment:关联视频;type:varchar(255);"`
-	SiteId     uint                 `json:"siteId" form:"siteId" gorm:"column:site_id;comment:站点id;type:bigint"`
-	SiteName   string               `json:"siteName" form:"siteName" gorm:"column:site_name;comment:站点id;type:bigint"`
-	Position   string               `json:"position" form:"position" gorm:"column:position;comment:经纬度;type:varchar(255);"`
-	Matter     string               `json:"matter" form:"matter" gorm:"column:matter;comment:问题列表;type:varchar(255);"`
-	SiteType   string               `json:"siteType" form:"siteType" gorm:"column:site_type;comment:站点类型;type:varchar(255);"`
-	Status     string               `json:"status" form:"status" gorm:"column:status;comment:处理状态;type:varchar(255);"`
-	Region     string               `json:"region" form:"region" gorm:"column:region;comment:区域;type:varchar(255);"`
-	HandImgs   string               `json:"handImgs" form:"handImgs" gorm:"column:hand_imgs;comment:处理图片;type:varchar(255);"`
-	HandText   string               `json:"handText" form:"handText" gorm:"column:hand_text;comment:处理内容;type:varchar(255);"`
-	Department string               `json:"department" form:"department" gorm:"column:department;comment:责任部门;type:varchar(255);"`
-	Remark     string               `json:"remark" form:"remark" gorm:"column:remark;comment:问题备注;type:varchar(600);"`
+	Oper       uint   `json:"oper" form:"oper" gorm:"column:oper;comment:发布人;type:bigint"`
+	Handler    *int   `json:"handler" form:"handler" gorm:"column:handler;comment:处理人;type:bigint"`
+	Imgs       string `json:"imgs" form:"imgs" gorm:"column:imgs;comment:关联图片;type:varchar(2000);"`
+	Video      string `json:"video" form:"video" gorm:"column:video;comment:关联视频;type:varchar(255);"`
+	SiteId     uint   `json:"siteId" form:"siteId" gorm:"column:site_id;comment:站点id;type:bigint"`
+	SiteName   string `json:"siteName" form:"siteName" gorm:"column:site_name;comment:站点id;type:bigint"`
+	Position   string `json:"position" form:"position" gorm:"column:position;comment:经纬度;type:varchar(255);"`
+	Matter     string `json:"matter" form:"matter" gorm:"column:matter;comment:问题列表;type:varchar(255);"`
+	SiteType   string `json:"siteType" form:"siteType" gorm:"column:site_type;comment:站点类型;type:varchar(255);"`
+	Status     string `json:"status" form:"status" gorm:"column:status;comment:处理状态;type:varchar(255);"`
+	Region     string `json:"region" form:"region" gorm:"column:region;comment:区域;type:varchar(255);"`
+	HandImgs   string `json:"handImgs" form:"handImgs" gorm:"column:hand_imgs;comment:处理图片;type:varchar(255);"`
+	HandText   string `json:"handText" form:"handText" gorm:"column:hand_text;comment:处理内容;type:varchar(255);"`
+	Department string `json:"department" form:"department" gorm:"column:department;comment:责任部门;type:varchar(255);"`
+	Remark     string `json:"remark" form:"remark" gorm:"column:remark;comment:问题备注;type:varchar(600);"`
+	Count      *int   `json:"count" form:"count" gorm:"default:0;column:count;comment:阅读次数;type:int);"`
+	Integral   *int   `json:"integral" form:"integral" gorm:"default:0;column:integral;comment:积分;type:int);"`
+	UnitName   *int   `json:"unitName" form:"unitName" gorm:"default:0;column:unit_name;comment:单位名称;type:varchar(255));"`
+	UnitId     *int   `json:"unitId" form:"unitId" gorm:"default:0;column:unit_id;comment:单位id;type:int);"`
 }
 
 // TableName ProblemInfo 表名

+ 21 - 0
server/model/autocode/read_count.go

@@ -0,0 +1,21 @@
+// 自动生成模板ReadCount
+package autocode
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+)
+
+// ReadCount 结构体
+// 如果含有time.Time 请自行import time包
+type ReadCount struct {
+	global.GVA_MODEL
+	ProblemId uint   `json:"problemId" form:"problemId" gorm:"column:problem_id;comment:问题id;type:bigint"`
+	UserId    uint   `json:"userId" form:"userId" gorm:"column:user_id;comment:阅读人id;type:bigint"`
+	UserName  string `json:"userName" form:"userName" gorm:"column:user_name;comment:阅读人用户名;type:varchar(255);"`
+	Count     *int   `json:"count" form:"count" gorm:"default:1;column:count;comment:阅读次数;type:int"`
+}
+
+// TableName ReadCount 表名
+func (ReadCount) TableName() string {
+	return "read_count"
+}

+ 11 - 0
server/model/autocode/request/ReadCountSearch.go

@@ -0,0 +1,11 @@
+package request
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/model/autocode"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+)
+
+type ReadCountSearch struct {
+	autocode.ReadCount
+	request.PageInfo
+}

+ 6 - 0
server/model/autocode/request/sendUser.go

@@ -0,0 +1,6 @@
+package request
+
+type SendUser struct {
+	ID        []string
+	ProblemID uint
+}

+ 11 - 0
server/model/request/read_count.go

@@ -0,0 +1,11 @@
+package request
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/model/autocode"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+)
+
+type ReadCountSearch struct{
+    autocode.ReadCount
+    request.PageInfo
+}

+ 1 - 0
server/model/system/request/sys_user.go

@@ -19,6 +19,7 @@ type RegisterWx struct {
 	Username  string `json:"username"`
 	NickName  string `json:"nickName"`
 	OpenId    string `json:"openId"`
+	UnionId   string `json:"unionId"`
 	HeaderImg string `json:"headerImg" gorm:"default:'http://www.henrongyi.top/avatar/lufu.jpg'"`
 }
 

+ 3 - 1
server/model/system/sys_user.go

@@ -18,5 +18,7 @@ type SysUser struct {
 	AuthorityId string         `json:"authorityId" gorm:"default:888;comment:用户角色ID"`                                 // 用户角色ID
 	Authority   SysAuthority   `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"`
 	Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"`
-	OpenId      string         `json:"openId" gorm:"comment:openid"` // openid
+	OpenId      string         `json:"openId" gorm:"comment:openid"`     // 小程序用户id
+	WechatId    string         `json:"wechatId" gorm:"comment:wechatid"` // 微信公众号用户id
+	UnionId     string         `json:"unionId" gorm:"comment:unionid"`   // 组合id
 }

+ 2 - 0
server/router/autocode/enter.go

@@ -6,5 +6,7 @@ type RouterGroup struct {
 	ContentRouter
 	PlaceRouter
 	ProblemInfoRouter
+	ReadCountRouter
+	UnitRouter
 	// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
 }

+ 2 - 0
server/router/autocode/problem_info.go

@@ -16,10 +16,12 @@ func (s *ProblemInfoRouter) InitProblemInfoRouter(Router *gin.RouterGroup) {
 	{
 		problemInfoRouter.POST("createProblemInfo", problemInfoApi.CreateProblemInfo)             // 新建ProblemInfo
 		problemInfoRouter.POST("exportExcel", problemInfoApi.ExportExcel)                         // 导出Excel
+		problemInfoRouter.POST("sendUser", problemInfoApi.SendUser)                               // 导出Excel
 		problemInfoRouter.DELETE("deleteProblemInfo", problemInfoApi.DeleteProblemInfo)           // 删除ProblemInfo
 		problemInfoRouter.DELETE("deleteProblemInfoByIds", problemInfoApi.DeleteProblemInfoByIds) // 批量删除ProblemInfo
 		problemInfoRouter.PUT("updateProblemInfo", problemInfoApi.UpdateProblemInfo)              // 更新ProblemInfo
 		problemInfoRouter.GET("getProblemInfoList", problemInfoApi.GetProblemInfoList)            // 获取ProblemInfo列表
+		problemInfoRouter.GET("findProblemPInfo", problemInfoApi.FindProblemPInfo)                // 根据ID获取ProblemInfo
 	}
 }
 

+ 24 - 0
server/router/autocode/read_count.go

@@ -0,0 +1,24 @@
+package autocode
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/api/v1"
+	"github.com/flipped-aurora/gin-vue-admin/server/middleware"
+	"github.com/gin-gonic/gin"
+)
+
+type ReadCountRouter struct {
+}
+
+// InitReadCountRouter 初始化 ReadCount 路由信息
+func (s *ReadCountRouter) InitReadCountRouter(Router *gin.RouterGroup) {
+	readCountRouter := Router.Group("readCount").Use(middleware.OperationRecord())
+	var readCountApi = v1.ApiGroupApp.AutoCodeApiGroup.ReadCountApi
+	{
+		readCountRouter.POST("createReadCount", readCountApi.CreateReadCount)   // 新建ReadCount
+		readCountRouter.DELETE("deleteReadCount", readCountApi.DeleteReadCount) // 删除ReadCount
+		readCountRouter.DELETE("deleteReadCountByIds", readCountApi.DeleteReadCountByIds) // 批量删除ReadCount
+		readCountRouter.PUT("updateReadCount", readCountApi.UpdateReadCount)    // 更新ReadCount
+		readCountRouter.GET("findReadCount", readCountApi.FindReadCount)        // 根据ID获取ReadCount
+		readCountRouter.GET("getReadCountList", readCountApi.GetReadCountList)  // 获取ReadCount列表
+	}
+}

+ 1 - 0
server/router/system/enter.go

@@ -14,4 +14,5 @@ type RouterGroup struct {
 	OperationRecordRouter
 	SysRouter
 	UserRouter
+	WechatRouter
 }

+ 17 - 0
server/router/system/wechat.go

@@ -0,0 +1,17 @@
+package system
+
+import (
+	v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
+	"github.com/gin-gonic/gin"
+)
+
+type WechatRouter struct {
+}
+
+func (s *WechatRouter) InitWechatRouter(Router *gin.RouterGroup) {
+	wechatRouter := Router.Group("wechat")
+	var wechatApi = v1.ApiGroupApp.SystemApiGroup.WechatApi
+	{
+		wechatRouter.Any("serve", wechatApi.Req)
+	}
+}

+ 2 - 0
server/service/autocode/enter.go

@@ -6,5 +6,7 @@ type ServiceGroup struct {
 	ContentService
 	PlaceService
 	ProblemInfoService
+	ReadCountService
+	UnitService
 	// Code generated by github.com/flipped-aurora/gin-vue-admin/server End; DO NOT EDIT.
 }

+ 6 - 0
server/service/autocode/problem_info.go

@@ -5,6 +5,7 @@ import (
 	"github.com/flipped-aurora/gin-vue-admin/server/model/autocode"
 	autoCodeReq "github.com/flipped-aurora/gin-vue-admin/server/model/autocode/request"
 	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+	"gorm.io/gorm"
 )
 
 type ProblemInfoService struct {
@@ -38,6 +39,11 @@ func (problemInfoService *ProblemInfoService) UpdateProblemInfo(problemInfo auto
 	return err
 }
 
+func (problemInfoService *ProblemInfoService) UpdateProblemInfoCount(id uint) (err error) {
+	err = global.GVA_DB.Model(&autocode.ProblemInfo{}).Where("id=?", id).Update("count", gorm.Expr("count+1")).Error
+	return err
+}
+
 // GetProblemInfo 根据id获取ProblemInfo记录
 // Author [piexlmax](https://github.com/piexlmax)
 func (problemInfoService *ProblemInfoService) GetProblemInfo(id uint) (err error, problemInfo autocode.ProblemInfo) {

+ 71 - 0
server/service/autocode/read_count.go

@@ -0,0 +1,71 @@
+package autocode
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/autocode"
+	autoCodeReq "github.com/flipped-aurora/gin-vue-admin/server/model/autocode/request"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+	"gorm.io/gorm"
+)
+
+type ReadCountService struct {
+}
+
+// CreateReadCount 创建ReadCount记录
+// Author [piexlmax](https://github.com/piexlmax)
+func (readCountService *ReadCountService) CreateReadCount(readCount autocode.ReadCount) (err error) {
+	err = global.GVA_DB.Create(&readCount).Error
+	return err
+}
+
+// DeleteReadCount 删除ReadCount记录
+// Author [piexlmax](https://github.com/piexlmax)
+func (readCountService *ReadCountService) DeleteReadCount(readCount autocode.ReadCount) (err error) {
+	err = global.GVA_DB.Delete(&readCount).Error
+	return err
+}
+
+// DeleteReadCountByIds 批量删除ReadCount记录
+// Author [piexlmax](https://github.com/piexlmax)
+func (readCountService *ReadCountService) DeleteReadCountByIds(ids request.IdsReq) (err error) {
+	err = global.GVA_DB.Delete(&[]autocode.ReadCount{}, "id in ?", ids.Ids).Error
+	return err
+}
+
+// UpdateReadCount 更新ReadCount记录
+// Author [piexlmax](https://github.com/piexlmax)
+func (readCountService *ReadCountService) UpdateReadCount(readCount autocode.ReadCount) (err error) {
+	err = global.GVA_DB.Save(&readCount).Error
+	return err
+}
+
+// GetReadCount 根据id获取ReadCount记录
+// Author [piexlmax](https://github.com/piexlmax)
+func (readCountService *ReadCountService) GetReadCountByUserId(userId int, problemId int) (err error, readCount autocode.ReadCount) {
+	err = global.GVA_DB.Where("user_id = ?", userId).Where("problem_id = ?", problemId).First(&readCount).Error
+	return
+}
+
+func (readCountService *ReadCountService) UpdateReadCountBy(id uint) (err error) {
+	err = global.GVA_DB.Model(&autocode.ReadCount{}).Where("id=?", id).Update("count", gorm.Expr("count+1")).Error
+	return err
+}
+
+func (readCountService *ReadCountService) GetReadCount(id uint) (err error, readCount autocode.ReadCount) {
+	err = global.GVA_DB.Where("id = ?", id).First(&readCount).Error
+	return
+}
+
+// GetReadCountInfoList 分页获取ReadCount记录
+// Author [piexlmax](https://github.com/piexlmax)
+func (readCountService *ReadCountService) GetReadCountInfoList(info autoCodeReq.ReadCountSearch) (err error, list interface{}, total int64) {
+	limit := info.PageSize
+	offset := info.PageSize * (info.Page - 1)
+	// 创建db
+	db := global.GVA_DB.Model(&autocode.ReadCount{})
+	var readCounts []autocode.ReadCount
+	// 如果有条件搜索 下方会自动创建搜索语句
+	err = db.Count(&total).Error
+	err = db.Limit(limit).Offset(offset).Find(&readCounts).Error
+	return err, readCounts, total
+}

+ 1 - 0
server/service/system/enter.go

@@ -15,4 +15,5 @@ type ServiceGroup struct {
 	OperationRecordService
 	SystemConfigService
 	UserService
+	WechatService
 }

+ 13 - 1
server/service/system/sys_user.go

@@ -84,7 +84,7 @@ func (userService *UserService) GetUserPInfoList(info systemReq.UserSearch) (err
 	}
 	var userList []system.SysUser
 	err = db.Count(&total).Error
-	err = db.Limit(limit).Offset(offset).Preload("Authorities").Preload("Authority").Find(&userList).Error
+	err = db.Limit(limit).Offset(offset).Preload("Authorities").Preload("Authority").Order("created_at desc").Find(&userList).Error
 	return err, userList, total
 }
 
@@ -171,6 +171,18 @@ func (userService *UserService) GetUserInfo(uuid uuid.UUID) (err error, user sys
 	return err, reqUser
 }
 
+func (userService *UserService) GetUserInfoByWechatId(wechatId string) (err error, user system.SysUser) {
+	var reqUser system.SysUser
+	err = global.GVA_DB.First(&reqUser, "wechat_id = ?", wechatId).Error
+	return err, reqUser
+}
+
+func (userService *UserService) GetUserInfoByUnionId(unionId string) (err error, user system.SysUser) {
+	var reqUser system.SysUser
+	err = global.GVA_DB.First(&reqUser, "union_id = ?", unionId).Error
+	return err, reqUser
+}
+
 //@author: [SliverHorn](https://github.com/SliverHorn)
 //@function: FindUserById
 //@description: 通过id获取用户信息

+ 9 - 0
server/service/system/wechat.go

@@ -0,0 +1,9 @@
+package system
+
+import (
+	"github.com/silenceper/wechat/v2/officialaccount"
+)
+
+type WechatService struct {
+	officialAccount *officialaccount.OfficialAccount
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 15536 - 1
web/package-lock.json


+ 17 - 0
web/src/api/problemInfo.js

@@ -17,6 +17,23 @@ export const createProblemInfo = (data) => {
   })
 }
 
+export const sendUserProblemInfo = (data) => {
+  return service({
+    url: '/problemInfo/sendUser',
+    method: 'post',
+    data
+  })
+}
+
+export const getReadCountList = (params) => {
+  return service({
+    url: '/readCount/getReadCountList',
+    method: 'get',
+    params
+  })
+}
+
+
 export const exportExcel = (data) => {
   service({
     url: '/problemInfo/exportExcel',

+ 97 - 0
web/src/api/unit.js

@@ -0,0 +1,97 @@
+import service from '@/utils/request'
+
+// @Tags Unit
+// @Summary 创建Unit
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body model.Unit true "创建Unit"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
+// @Router /unit/createUnit [post]
+export const createUnit = (data) => {
+  return service({
+    url: '/unit/createUnit',
+    method: 'post',
+    data
+  })
+}
+
+// @Tags Unit
+// @Summary 删除Unit
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body model.Unit true "删除Unit"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
+// @Router /unit/deleteUnit [delete]
+export const deleteUnit = (data) => {
+  return service({
+    url: '/unit/deleteUnit',
+    method: 'delete',
+    data
+  })
+}
+
+// @Tags Unit
+// @Summary 删除Unit
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body request.IdsReq true "批量删除Unit"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
+// @Router /unit/deleteUnit [delete]
+export const deleteUnitByIds = (data) => {
+  return service({
+    url: '/unit/deleteUnitByIds',
+    method: 'delete',
+    data
+  })
+}
+
+// @Tags Unit
+// @Summary 更新Unit
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data body model.Unit true "更新Unit"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
+// @Router /unit/updateUnit [put]
+export const updateUnit = (data) => {
+  return service({
+    url: '/unit/updateUnit',
+    method: 'put',
+    data
+  })
+}
+
+// @Tags Unit
+// @Summary 用id查询Unit
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data query model.Unit true "用id查询Unit"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
+// @Router /unit/findUnit [get]
+export const findUnit = (params) => {
+  return service({
+    url: '/unit/findUnit',
+    method: 'get',
+    params
+  })
+}
+
+// @Tags Unit
+// @Summary 分页获取Unit列表
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Param data query request.PageInfo true "分页获取Unit列表"
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
+// @Router /unit/getUnitList [get]
+export const getUnitList = (params) => {
+  return service({
+    url: '/unit/getUnitList',
+    method: 'get',
+    params
+  })
+}

+ 91 - 3
web/src/view/problemInfo/problemInfo.vue

@@ -43,6 +43,9 @@
       <el-table-column label="发布人" prop="oper" width="120"/>
       <el-table-column label="站点" prop="siteName" width="220"/>
       <el-table-column label="站点类型" prop="siteType" width="120"/>
+      <el-table-column label="已登录查阅次数" prop="count" width="120"/>
+      <el-table-column label="一类单位" prop="unitName" width="120"/>
+      <el-table-column label="分数" prop="integral" width="120"/>
       <el-table-column label="处理状态" prop="status" width="120">
         <template #default="scope">
           <el-tag v-show="scope.row.status == 'Untreated'" type="warning">未处理</el-tag>
@@ -61,6 +64,8 @@
           </el-button>
           <el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteRow(scope.row)">删除</el-button>
           <el-button type="small" icon="el-icon-download" size="mini" @click="handlePdf(scope.row)">导出为pdf</el-button>
+          <el-button type="small" icon="el-icon-s-comment" size="mini" @click="openUser(scope.row)">发送公众号通知</el-button>
+          <el-button type="small" icon="el-icon-user" size="mini" @click="showReadInfo(scope.row)">已查阅详情</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -74,6 +79,46 @@
         @current-change="handleCurrentChange"
         @size-change="handleSizeChange"
     />
+    <el-dialog title="选择通知人" v-model="noticeList" width="500px" append-to-body>
+      <el-form v-model="noticeUser" label-width="120px">
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="选择通知人" :rules="{required: true, message: '请选择通知人'}">
+              <el-select
+                  v-model="noticeUser.userList"
+                  filterable
+                  clearable
+                  multiple
+                  size="small"
+                  style="width: 240px"
+              >
+                <el-option
+                    v-for="id in Object.keys(userIds)"
+                    :key="id"
+                    :label="userIds[id]"
+                    :value="id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="sendUser">确 定</el-button>
+        <el-button @click="closeSend">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog
+        title="已阅详情"
+        v-model="dialogVisibleRead"
+        width="30%">
+      <div style="text-align: center;padding-bottom: 20px">
+        <span>{{ readMsg }}</span>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="closeRead">确 定</el-button>
+      </div>
+    </el-dialog>
     <el-dialog ref="problemInfo" v-model="dialogFormVisible" id="problemInfo" :before-close="closeDialog" title="问题详情">
       <el-form :model="formData" label-position="right" label-width="80px">
         <el-card class="box-card">
@@ -147,10 +192,11 @@ import {
   updateProblemInfo,
   findProblemInfo,
   getProblemInfoList,
-  exportExcel
+  exportExcel, sendUserProblemInfo, getReadCountList
 } from '@/api/problemInfo' //  此处请自行替换地址
 import infoList from '@/mixins/infoList'
-import { getDict } from '@/utils/dictionary'
+import {getDict} from '@/utils/dictionary'
+import {getUserPList} from "@/api/user";
 
 export default {
   name: 'ProblemInfo',
@@ -161,6 +207,14 @@ export default {
       dialogFormVisible: false,
       type: '',
       siteType: [],
+      noticeList: false,
+      userIds: {},
+      dialogVisibleRead: false,
+      readMsg: '',
+      noticeUser: {
+        userList: []
+      },
+      sendId: 0,
       deleteVisible: false,
       multipleSelection: [],
       matterList: [],
@@ -212,7 +266,41 @@ export default {
     async handlePdf(row) {
       const href = window.location.origin
       const params = `/#/proInfo?Id=${row.ID}`
-      window.open(href + params, '_blank','width=1200,height=1000,location=no,toolbar=no,status=no,scrollbars=yes,titlebar=no,')
+      window.open(href + params, '_blank', 'width=1200,height=1000,location=no,toolbar=no,status=no,scrollbars=yes,titlebar=no,')
+    },
+    async openUser(row) {
+      this.sendId = row.ID
+      this.noticeList = true
+      getUserPList({page: 1, pageSize: 9999}).then(res => {
+        for (const user in res.data.list) {
+          this.userIds[res.data.list[user].ID] = res.data.list[user].userName
+        }
+      })
+    },
+    sendUser() {
+      sendUserProblemInfo({ID: this.noticeUser.userList, ProblemID: this.sendId}).then(res => {
+        console.log(res)
+        this.closeSend()
+      })
+    },
+    closeSend() {
+      this.noticeList = false
+      this.userIds = {}
+      this.noticeUser.userList = []
+      this.sendId = 0
+    },
+    showReadInfo(row) {
+      getReadCountList({page: 1, pageSize: 9999, problemId: row.ID}).then(res => {
+        this.dialogVisibleRead = true;
+        this.readMsg = ''
+        for (const read in res.data.list) {
+          this.readMsg=this.readMsg.concat(res.data.list[read].userName + ':' + res.data.list[read].count + '次、')
+        }
+      })
+    },
+    closeRead() {
+      this.dialogVisibleRead = false;
+      this.readMsg = ''
     },
     async onDelete() {
       const ids = []

+ 205 - 0
web/src/view/unit/unit.vue

@@ -0,0 +1,205 @@
+<template>
+  <div>
+    <div class="search-term">
+      <el-form :inline="true" :model="searchInfo" class="demo-form-inline">
+        <el-form-item>
+          <el-button size="mini" type="primary" icon="el-icon-search" @click="onSubmit">查询</el-button>
+          <el-button size="mini" type="primary" icon="el-icon-plus" @click="openDialog">新增</el-button>
+          <el-popover v-model:visible="deleteVisible" placement="top" width="160">
+            <p>确定要删除吗?</p>
+            <div style="text-align: right; margin: 0">
+              <el-button size="mini" type="text" @click="deleteVisible = false">取消</el-button>
+              <el-button size="mini" type="primary" @click="onDelete">确定</el-button>
+            </div>
+            <template #reference>
+              <el-button icon="el-icon-delete" size="mini" type="danger" style="margin-left: 10px;">批量删除</el-button>
+            </template>
+          </el-popover>
+        </el-form-item>
+      </el-form>
+    </div>
+    <el-table
+      ref="multipleTable"
+      border
+      stripe
+      style="width: 100%"
+      tooltip-effect="dark"
+      :data="tableData"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" />
+      <el-table-column label="日期" width="180">
+        <template #default="scope">{{ formatDate(scope.row.CreatedAt) }}</template>
+      </el-table-column>
+      <el-table-column label="单位名称" prop="unitName" width="120" />
+      <el-table-column label="现有积分" prop="unitIntegral" width="120" />
+      <el-table-column label="按钮组">
+        <template #default="scope">
+          <el-button size="small" type="primary" icon="el-icon-edit" class="table-button" @click="updateUnit(scope.row)">变更</el-button>
+          <el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteRow(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      layout="total, sizes, prev, pager, next, jumper"
+      :current-page="page"
+      :page-size="pageSize"
+      :page-sizes="[10, 30, 50, 100]"
+      :style="{float:'right',padding:'20px'}"
+      :total="total"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    />
+    <el-dialog v-model="dialogFormVisible" :before-close="closeDialog" title="弹窗操作">
+      <el-form :model="formData" label-position="right" label-width="80px">
+        <el-form-item label="单位名称:">
+          <el-input v-model="formData.unitName" clearable placeholder="请输入" />
+        </el-form-item>
+        <el-form-item label="现有积分:">
+          <el-input v-model.number="formData.unitIntegral" clearable placeholder="请输入" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="closeDialog">取 消</el-button>
+          <el-button type="primary" @click="enterDialog">确 定</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  createUnit,
+  deleteUnit,
+  deleteUnitByIds,
+  updateUnit,
+  findUnit,
+  getUnitList
+} from '@/api/unit' //  此处请自行替换地址
+import infoList from '@/mixins/infoList'
+export default {
+  name: 'Unit',
+  mixins: [infoList],
+  data() {
+    return {
+      listApi: getUnitList,
+      dialogFormVisible: false,
+      type: '',
+      deleteVisible: false,
+      multipleSelection: [],
+      formData: {
+        unitName: '',
+        unitIntegral: 0,
+      }
+    }
+  },
+  async created() {
+    await this.getTableData()
+  },
+  methods: {
+  // 条件搜索前端看此方法
+    onSubmit() {
+      this.page = 1
+      this.pageSize = 10
+      this.getTableData()
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    deleteRow(row) {
+      this.$confirm('确定要删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.deleteUnit(row)
+      })
+    },
+    async onDelete() {
+      const ids = []
+      if (this.multipleSelection.length === 0) {
+        this.$message({
+          type: 'warning',
+          message: '请选择要删除的数据'
+        })
+        return
+      }
+      this.multipleSelection &&
+        this.multipleSelection.map(item => {
+          ids.push(item.ID)
+        })
+      const res = await deleteUnitByIds({ ids })
+      if (res.code === 0) {
+        this.$message({
+          type: 'success',
+          message: '删除成功'
+        })
+        if (this.tableData.length === ids.length && this.page > 1) {
+          this.page--
+        }
+        this.deleteVisible = false
+        this.getTableData()
+      }
+    },
+    async updateUnit(row) {
+      const res = await findUnit({ ID: row.ID })
+      this.type = 'update'
+      if (res.code === 0) {
+        this.formData = res.data.reunit
+        this.dialogFormVisible = true
+      }
+    },
+    closeDialog() {
+      this.dialogFormVisible = false
+      this.formData = {
+        unitName: '',
+        unitIntegral: 0,
+      }
+    },
+    async deleteUnit(row) {
+      const res = await deleteUnit({ ID: row.ID })
+      if (res.code === 0) {
+        this.$message({
+          type: 'success',
+          message: '删除成功'
+        })
+        if (this.tableData.length === 1 && this.page > 1) {
+          this.page--
+        }
+        this.getTableData()
+      }
+    },
+    async enterDialog() {
+      let res
+      switch (this.type) {
+        case 'create':
+          res = await createUnit(this.formData)
+          break
+        case 'update':
+          res = await updateUnit(this.formData)
+          break
+        default:
+          res = await createUnit(this.formData)
+          break
+      }
+      if (res.code === 0) {
+        this.$message({
+          type: 'success',
+          message: '创建/更改成功'
+        })
+        this.closeDialog()
+        this.getTableData()
+      }
+    },
+    openDialog() {
+      this.type = 'create'
+      this.dialogFormVisible = true
+    }
+  },
+}
+</script>
+
+<style>
+</style>

+ 78 - 0
web/src/view/unit/unitForm.vue

@@ -0,0 +1,78 @@
+<template>
+  <div>
+    <el-form :model="formData" label-position="right" label-width="80px">
+      <el-form-item label="单位名称:">
+        <el-input v-model="formData.unitName" clearable placeholder="请输入" />
+      </el-form-item>
+      <el-form-item label="现有积分:">
+        <el-input v-model.number="formData.unitIntegral" clearable placeholder="请输入" />
+      </el-form-item>
+      <el-form-item>
+        <el-button size="mini" type="primary" @click="save">保存</el-button>
+        <el-button size="mini" type="primary" @click="back">返回</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import {
+  createUnit,
+  updateUnit,
+  findUnit
+} from '@/api/unit' //  此处请自行替换地址
+import infoList from '@/mixins/infoList'
+export default {
+  name: 'Unit',
+  mixins: [infoList],
+  data() {
+    return {
+      type: '',
+      formData: {
+        unitName: '',
+        unitIntegral: 0,
+      }
+    }
+  },
+  async created() {
+    // 建议通过url传参获取目标数据ID 调用 find方法进行查询数据操作 从而决定本页面是create还是update 以下为id作为url参数示例
+    if (this.$route.query.id) {
+      const res = await findUnit({ ID: this.$route.query.id })
+      if (res.code === 0) {
+        this.formData = res.data.reunit
+        this.type = 'update'
+      }
+    } else {
+      this.type = 'create'
+    }
+  },
+  methods: {
+    async save() {
+      let res
+      switch (this.type) {
+        case 'create':
+          res = await createUnit(this.formData)
+          break
+        case 'update':
+          res = await updateUnit(this.formData)
+          break
+        default:
+          res = await createUnit(this.formData)
+          break
+      }
+      if (res.code === 0) {
+        this.$message({
+          type: 'success',
+          message: '创建/更改成功'
+        })
+      }
+    },
+    back() {
+      this.$router.go(-1)
+    }
+  }
+}
+</script>
+
+<style>
+</style>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 426 - 588
web/yarn.lock


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác