Browse Source

fix: 问答社区

hsun 2 years ago
parent
commit
1d6b2717b5

+ 132 - 9
controller/community/question.go

@@ -1,14 +1,33 @@
 package community
 
 import (
+	"fmt"
 	"github.com/gin-gonic/gin"
 	"hongze/hongze_yb/controller/response"
+	"hongze/hongze_yb/global"
 	"hongze/hongze_yb/models/request"
+	respond "hongze/hongze_yb/models/response"
+	"hongze/hongze_yb/services"
 	"hongze/hongze_yb/services/community"
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/utils"
+	"os"
+	"path"
+	"time"
 )
 
+// QuestionList 问答列表
+// @Tags 问答社区模块
+// @Description 获取问答列表
+// @Param page_index			query int false "页码"
+// @Param page_size				query int false "每页数量"
+// @Param only_mine				query int false "只看我的"
+// @Param chart_permission_id	query int false "品种权限ID"
+// @Param reply_status			query int false "回复状态 0-全部 2-待回答 3-已回答"
+// @Param replier_user_id		query int false "回复人ID"
+// @Success 200 {object} respond.CommunityQuestionList
+// @failure 400 {string} string "获取失败"
+// @Router /question/list [get]
 func QuestionList(c *gin.Context) {
 	var req request.QuestionListReq
 	if err := c.Bind(&req); err != nil {
@@ -30,6 +49,13 @@ func QuestionList(c *gin.Context) {
 	response.OkData("获取成功", list, c)
 }
 
+// QuestionDetail 问答详情
+// @Tags 问答社区模块
+// @Description 获取问答详情
+// @Param question_id  query  int  true  "问答ID"
+// @Success 200 {object} respond.CommunityQuestionItem
+// @failure 400 {string} string "获取失败"
+// @Router /question/detail [get]
 func QuestionDetail(c *gin.Context) {
 	var req request.QuestionDetailReq
 	if err := c.Bind(&req); err != nil {
@@ -48,7 +74,14 @@ func QuestionDetail(c *gin.Context) {
 	response.OkData("获取成功", item, c)
 }
 
-func AskQuestion(c *gin.Context) {
+// QuestionAsk 发布提问
+// @Tags 问答社区模块
+// @Description 发布提问
+// @Param question_content  query  string  true  "问题内容"
+// @Success 200 {string} string "操作成功"
+// @failure 400 {string} string "操作失败"
+// @Router /question/ask [post]
+func QuestionAsk(c *gin.Context) {
 	var req request.QuestionAskReq
 	if err := c.ShouldBind(&req); err != nil {
 		response.Fail("参数有误", c)
@@ -60,14 +93,22 @@ func AskQuestion(c *gin.Context) {
 		return
 	}
 	userinfo := user.GetInfoByClaims(c)
-	if err := community.CreateQuestion(int(userinfo.UserID), userinfo.Mobile, userinfo.RealName, req.QuestionContent); err != nil {
-		response.FailMsg("提交失败", "AskQuestion ErrMsg:"+err.Error(), c)
+	if err := community.CreateQuestion(int(userinfo.UserID), userinfo.Mobile, userinfo.OpenID, userinfo.RealName, req.QuestionContent); err != nil {
+		response.FailMsg("提交失败", "QuestionAsk ErrMsg:"+err.Error(), c)
 		return
 	}
 	response.Ok("操作成功", c)
 }
 
-func ReplyQuestion(c *gin.Context) {
+// QuestionReply 发布回复
+// @Tags 问答社区模块
+// @Description 发布回复
+// @Param question_id	query  int		true  "问答ID"
+// @Param audio_list	query  object	true  "音频列表"
+// @Success 200 {string} string "操作成功"
+// @failure 400 {string} string "操作失败"
+// @Router /question/reply [post]
+func QuestionReply(c *gin.Context) {
 	var req request.QuestionReplyReq
 	if err := c.ShouldBind(&req); err != nil {
 		response.Fail("参数有误", c)
@@ -83,13 +124,20 @@ func ReplyQuestion(c *gin.Context) {
 	}
 	userinfo := user.GetInfoByClaims(c)
 	if err := community.ReplyUserQuestion(int(userinfo.UserID), req.QuestionId, req.AudioList); err != nil {
-		response.FailMsg("提交失败", "ReplyQuestion ErrMsg:"+err.Error(), c)
+		response.FailMsg("提交失败", "QuestionReply ErrMsg:"+err.Error(), c)
 		return
 	}
 	response.Ok("操作成功", c)
 }
 
-func ReadReply(c *gin.Context) {
+// QuestionReplyRead 已读回复
+// @Tags 问答社区模块
+// @Description 已读回复
+// @Param question_id  query  int  true  "问答ID"
+// @Success 200 {string} string "操作成功"
+// @failure 400 {string} string "操作失败"
+// @Router /question/reply/read [post]
+func QuestionReplyRead(c *gin.Context) {
 	var req request.QuestionReadReq
 	if err := c.ShouldBind(&req); err != nil {
 		response.Fail("参数有误", c)
@@ -101,13 +149,20 @@ func ReadReply(c *gin.Context) {
 	}
 	userinfo := user.GetInfoByClaims(c)
 	if err := community.ReadQuestionReply(int(userinfo.UserID), req.QuestionId); err != nil {
-		response.FailMsg("操作失败", "ReadReply ErrMsg:"+err.Error(), c)
+		response.FailMsg("操作失败", "QuestionReplyRead ErrMsg:"+err.Error(), c)
 		return
 	}
 	response.Ok("操作成功", c)
 }
 
-func ReplyListTotal(c *gin.Context) {
+// QuestionReplyTotal 问答列表数量统计
+// @Tags 问答社区模块
+// @Description 问答列表数量统计
+// @Param replier_user_id  query  int  true  "回复人ID"
+// @Success 200 {object} respond.CommunityReplyTotal
+// @failure 400 {string} string "获取失败"
+// @Router /question/reply/total [get]
+func QuestionReplyTotal(c *gin.Context) {
 	var req request.ReplyListTotalReq
 	if err := c.ShouldBind(&req); err != nil {
 		response.Fail("参数有误", c)
@@ -119,8 +174,76 @@ func ReplyListTotal(c *gin.Context) {
 	}
 	resp, err := community.GetReplyListTotal(req.ReplierUserId)
 	if err != nil {
-		response.FailMsg("获取失败", "ReplyListTotal ErrMsg:"+err.Error(), c)
+		response.FailMsg("获取失败", "QuestionReplyTotal ErrMsg:"+err.Error(), c)
 		return
 	}
 	response.OkData("获取成功", resp, c)
 }
+
+// QuestionUploadAudio 上传回复音频
+// @Tags 问答社区模块
+// @Description 上传回复音频
+// @Param file  query  string  true  "音频文件"
+// @Success 200 {string} string "上传成功"
+// @failure 400 {string} string "上传失败"
+// @Router /question/reply/upload_audio [post]
+func QuestionUploadAudio(c *gin.Context) {
+	file, err := c.FormFile("file")
+	if err != nil {
+		response.FailMsg("获取资源失败", "获取资源失败, Err:"+err.Error(), c)
+		return
+	}
+	ext := path.Ext(file.Filename)
+	if ext != ".mp3" {
+		response.Fail("暂仅支持mp3格式", c)
+		return
+	}
+	dateDir := time.Now().Format("20060102")
+	localDir := global.CONFIG.Serve.StaticDir + "hongze/" + dateDir
+	if err := os.MkdirAll(localDir, 0766); err != nil {
+		response.FailMsg("存储目录创建失败", "QuestionUploadAudio 存储目录创建失败, Err:"+err.Error(), c)
+		return
+	}
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	filtName := randStr + ext
+	fpath := localDir + "/" + filtName
+	defer func() {
+		_ = os.Remove(fpath)
+	}()
+	// 生成文件至指定目录
+	if err := c.SaveUploadedFile(file, fpath); err != nil {
+		response.FailMsg("文件生成失败", "QuestionUploadAudio 文件生成失败, Err:"+err.Error(), c)
+		return
+	}
+	// 获取音频文件时长
+	fByte, err := os.ReadFile(fpath)
+	if err != nil {
+		response.FailMsg("读取本地文件失败", "QuestionUploadAudio 读取本地文件失败", c)
+		return
+	}
+	seconds, err := services.GetMP3PlayDuration(fByte)
+	if err != nil {
+		response.FailMsg("读取文件时长失败", "QuestionUploadAudio 读取文件时长失败", c)
+		return
+	}
+	// 音频大小MB
+	fi, err := os.Stat(fpath)
+	if err != nil {
+		response.FailMsg("读取文件大小失败", "QuestionUploadAudio 读取文件大小失败", c)
+		return
+	}
+	mb := utils.Bit2MB(fi.Size(), 2)
+	// 上传文件至阿里云
+	ossDir := "yb_wx/community_question_audio/"
+	resourceUrl, err := services.UploadAliyunToDir(filtName, fpath, ossDir)
+	if err != nil {
+		response.FailMsg("文件上传失败", "QuestionUploadAudio 文件上传失败, Err:"+err.Error(), c)
+		return
+	}
+	resp := &respond.CommunityQuestionAudioUpload{
+		AudioURL:         resourceUrl,
+		AudioPlaySeconds: fmt.Sprint(seconds),
+		AudioSize:        fmt.Sprint(mb),
+	}
+	response.OkData("上传成功", resp, c)
+}

+ 1 - 1
controller/wechat/wechat.go

@@ -143,7 +143,7 @@ func GetEncryptInfo(c *gin.Context) {
 // @Title 微信获取签名接口
 // @Description 微信获取签名接口
 // @Param   Url   query   string  true       "url地址"
-// @Success 200 {object} models.WechatSign
+// @Success 200 {string} string "获取成功"
 // @router /getWxJsConf [get]
 func GetWxJsConf(c *gin.Context) {
 	getUrl := c.DefaultQuery("Url", "")

File diff suppressed because it is too large
+ 794 - 47
docs/docs.go


File diff suppressed because it is too large
+ 794 - 47
docs/swagger.json


+ 513 - 3
docs/swagger.yaml

@@ -78,6 +78,8 @@ definitions:
     type: object
   admin.Admin:
     properties:
+      adminAvatar:
+        type: string
       adminName:
         type: string
       authority:
@@ -136,7 +138,7 @@ definitions:
         description: 角色编码
         type: string
     type: object
-  chart_edb_mapping.ChartEdbInfoMapping:
+  chart_edb_mapping.ChartEdbInfoMappingList:
     properties:
       chartColor:
         type: string
@@ -192,13 +194,20 @@ definitions:
       unit:
         type: string
     type: object
+  chart_info.ChartBeforeNext:
+    properties:
+      nextChart:
+        $ref: '#/definitions/chart_info.ChartSortInfo'
+      prevChart:
+        $ref: '#/definitions/chart_info.ChartSortInfo'
+    type: object
   chart_info.ChartInfoDetailResp:
     properties:
       chartInfo:
         $ref: '#/definitions/chart_info.ChartInfoView'
       edbInfoList:
         items:
-          $ref: '#/definitions/chart_edb_mapping.ChartEdbInfoMapping'
+          $ref: '#/definitions/chart_edb_mapping.ChartEdbInfoMappingList'
         type: array
     type: object
   chart_info.ChartInfoView:
@@ -215,6 +224,8 @@ definitions:
         type: integer
       chartName:
         type: string
+      chartSource:
+        type: string
       chartType:
         type: integer
       createTime:
@@ -285,6 +296,23 @@ definitions:
       minData:
         type: number
     type: object
+  chart_info.ChartSortInfo:
+    properties:
+      chartInfoId:
+        type: integer
+      myChartClassifyId:
+        type: integer
+      myChartClassifyName:
+        type: string
+      myChartId:
+        type: integer
+      sort:
+        type: integer
+      switch:
+        type: integer
+      uniqueCode:
+        type: string
+    type: object
   chart_info.SaveChartInfoReq:
     properties:
       calendar:
@@ -314,6 +342,26 @@ definitions:
       startDate:
         type: string
     type: object
+  company.FiccPermissionList:
+    properties:
+      classifyName:
+        type: string
+      hasPermission:
+        type: boolean
+      items:
+        items:
+          $ref: '#/definitions/company.PermissionItem'
+        type: array
+    type: object
+  company.PermissionItem:
+    properties:
+      hasPermission:
+        type: boolean
+      permissionId:
+        type: integer
+      permissionName:
+        type: string
+    type: object
   logic.ApplyVariety:
     properties:
       name:
@@ -395,7 +443,7 @@ definitions:
       seasonStartDate:
         type: string
       sort:
-        type: integer
+        type: number
       startDate:
         type: string
       sysUserId:
@@ -435,6 +483,85 @@ definitions:
         description: 排序字段,值越小,越靠前
         type: integer
     type: object
+  response.CommunityQuestionAudioItem:
+    properties:
+      audio_play_seconds:
+        type: string
+      audio_size:
+        type: string
+      audio_url:
+        type: string
+      community_question_id:
+        type: integer
+      sort:
+        type: integer
+    type: object
+  response.CommunityQuestionItem:
+    properties:
+      audio_list:
+        items:
+          $ref: '#/definitions/response.CommunityQuestionAudioItem'
+        type: array
+      auth_ok:
+        type: boolean
+      chart_permission_id:
+        type: integer
+      chart_permission_name:
+        type: string
+      community_question_id:
+        type: integer
+      create_time:
+        type: string
+      is_read:
+        type: integer
+      is_top:
+        type: integer
+      question_content:
+        type: string
+      replier_avatar:
+        type: string
+      replier_rank:
+        type: string
+      replier_real_name:
+        type: string
+      reply_time:
+        type: string
+      user_id:
+        type: integer
+    type: object
+  response.CommunityQuestionList:
+    properties:
+      permissionInfo:
+        $ref: '#/definitions/response.PermissionCheckInfo'
+      questionList:
+        items:
+          $ref: '#/definitions/response.CommunityQuestionItem'
+        type: array
+    type: object
+  response.CommunityReplyTotal:
+    properties:
+      replied:
+        type: integer
+      total:
+        type: integer
+      wait:
+        type: integer
+    type: object
+  response.CustomerInfo:
+    properties:
+      company_name:
+        type: string
+      has_apply:
+        type: boolean
+      is_suspend:
+        type: integer
+      mobile:
+        type: string
+      name:
+        type: string
+      status:
+        type: string
+    type: object
   response.LoginResp:
     properties:
       authorization:
@@ -444,18 +571,48 @@ definitions:
       user_id:
         type: integer
     type: object
+  response.PermissionCheckInfo:
+    properties:
+      customer_info:
+        $ref: '#/definitions/response.CustomerInfo'
+      hz_phone:
+        type: string
+      mobile:
+        type: string
+      name:
+        type: string
+      type:
+        type: string
+    type: object
+  services.SharePosterReq:
+    properties:
+      code_page:
+        type: string
+      code_scene:
+        type: string
+      pars:
+        type: string
+      source:
+        type: string
+      version:
+        type: string
+    type: object
   user.ApplyReq:
     properties:
       business_card_url:
         type: string
       company_name:
         type: string
+      from_page:
+        type: string
       permission:
         type: string
       real_name:
         type: string
       source:
         type: integer
+      source_agent:
+        type: integer
     type: object
   user.CompanyPermission:
     properties:
@@ -1005,6 +1162,47 @@ paths:
       summary: 获取图表列表
       tags:
       - 图库模块
+  /company/permission/tree:
+    get:
+      consumes:
+      - application/json
+      description: 获取FICC品种权限列表
+      parameters:
+      - description: Bearer 31a165baebe6dec616b1f8f3207b4273
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/company.FiccPermissionList'
+            type: array
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      security:
+      - ApiKeyAuth: []
+      summary: 获取FICC品种权限列表
+      tags:
+      - 客户模块
+  /getWxJsConf:
+    get:
+      description: 微信获取签名接口
+      parameters:
+      - description: url地址
+        in: query
+        name: Url
+        required: true
+        type: string
+      responses:
+        "200":
+          description: 获取成功
+          schema:
+            type: string
   /my_chart/editChartInfo:
     post:
       consumes:
@@ -1036,6 +1234,39 @@ paths:
       summary: 编辑图表信息
       tags:
       - 图库模块
+  /my_chart/getChartBeforeAndNext:
+    get:
+      consumes:
+      - application/json
+      description: 获取当前图表上一张及下一张信息
+      parameters:
+      - description: Bearer 31a165baebe6dec616b1f8f3207b4273
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: 我的图表ID
+        in: query
+        name: MyChartId
+        type: string
+      - description: 我的图表分类ID
+        in: query
+        name: MyChartClassifyId
+        type: string
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/chart_info.ChartBeforeNext'
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      security:
+      - ApiKeyAuth: []
+      summary: 获取当前图表上一张及下一张信息
+      tags:
+      - 图库模块
   /my_chart/getChartInfoDetail:
     get:
       consumes:
@@ -1132,6 +1363,37 @@ paths:
       summary: 移动我的图表分类
       tags:
       - 图库模块
+  /my_chart/refreshChartInfo:
+    post:
+      consumes:
+      - application/json
+      description: 刷新图表信息
+      parameters:
+      - description: Bearer 31a165baebe6dec616b1f8f3207b4273
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: 请求参数
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/chart_info.SaveChartInfoReq'
+      responses:
+        "200":
+          description: 操作成功
+          schema:
+            type: string
+        "400":
+          description: 操作失败
+          schema:
+            type: string
+      security:
+      - ApiKeyAuth: []
+      summary: 刷新图表信息
+      tags:
+      - 图库模块
   /public/get_apply_variety_list:
     get:
       consumes:
@@ -1159,6 +1421,60 @@ paths:
       summary: 获取所有可以申请的品种权限列表
       tags:
       - 公共模块
+  /public/get_share_poster:
+    post:
+      consumes:
+      - application/json
+      description: 获取分享海报
+      parameters:
+      - description: type json string
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/services.SharePosterReq'
+      responses:
+        "200":
+          description: 获取成功
+          schema:
+            type: string
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      security:
+      - ApiKeyAuth: []
+      summary: 获取分享海报
+      tags:
+      - 公共模块
+  /public/get_suncode_scene:
+    get:
+      description: 获取小程序太阳码scene值
+      parameters:
+      - description: Bearer 31a165baebe6dec616b1f8f3207b4273
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: scene_key值
+        in: query
+        name: scene_key
+        required: true
+        type: string
+      responses:
+        "200":
+          description: 获取成功
+          schema:
+            type: string
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      security:
+      - ApiKeyAuth: []
+      summary: 获取小程序太阳码scene值
+      tags:
+      - 公共模块
   /public/upload:
     post:
       consumes:
@@ -1188,6 +1504,170 @@ paths:
       summary: 文件上传
       tags:
       - 公共模块
+  /question/ask:
+    post:
+      description: 发布提问
+      parameters:
+      - description: 问题内容
+        in: query
+        name: question_content
+        required: true
+        type: string
+      responses:
+        "200":
+          description: 操作成功
+          schema:
+            type: string
+        "400":
+          description: 操作失败
+          schema:
+            type: string
+      tags:
+      - 问答社区模块
+  /question/detail:
+    get:
+      description: 获取问答详情
+      parameters:
+      - description: 问答ID
+        in: query
+        name: question_id
+        required: true
+        type: integer
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/response.CommunityQuestionItem'
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      tags:
+      - 问答社区模块
+  /question/list:
+    get:
+      description: 获取问答列表
+      parameters:
+      - description: 页码
+        in: query
+        name: page_index
+        type: integer
+      - description: 每页数量
+        in: query
+        name: page_size
+        type: integer
+      - description: 只看我的
+        in: query
+        name: only_mine
+        type: integer
+      - description: 品种权限ID
+        in: query
+        name: chart_permission_id
+        type: integer
+      - description: 回复状态 0-全部 2-待回答 3-已回答
+        in: query
+        name: reply_status
+        type: integer
+      - description: 回复人ID
+        in: query
+        name: replier_user_id
+        type: integer
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/response.CommunityQuestionList'
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      tags:
+      - 问答社区模块
+  /question/reply:
+    post:
+      description: 发布回复
+      parameters:
+      - description: 问答ID
+        in: query
+        name: question_id
+        required: true
+        type: integer
+      - description: 音频列表
+        in: query
+        name: audio_list
+        required: true
+        type: object
+      responses:
+        "200":
+          description: 操作成功
+          schema:
+            type: string
+        "400":
+          description: 操作失败
+          schema:
+            type: string
+      tags:
+      - 问答社区模块
+  /question/reply/read:
+    post:
+      description: 已读回复
+      parameters:
+      - description: 问答ID
+        in: query
+        name: question_id
+        required: true
+        type: integer
+      responses:
+        "200":
+          description: 操作成功
+          schema:
+            type: string
+        "400":
+          description: 操作失败
+          schema:
+            type: string
+      tags:
+      - 问答社区模块
+  /question/reply/total:
+    get:
+      description: 问答列表数量统计
+      parameters:
+      - description: 回复人ID
+        in: query
+        name: replier_user_id
+        required: true
+        type: integer
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/response.CommunityReplyTotal'
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      tags:
+      - 问答社区模块
+  /question/reply/upload_audio:
+    post:
+      description: 上传回复音频
+      parameters:
+      - description: 音频文件
+        in: query
+        name: file
+        required: true
+        type: string
+      responses:
+        "200":
+          description: 上传成功
+          schema:
+            type: string
+        "400":
+          description: 上传失败
+          schema:
+            type: string
+      tags:
+      - 问答社区模块
   /report/research_report:
     get:
       consumes:
@@ -1218,6 +1698,36 @@ paths:
       summary: 获取报告详情
       tags:
       - 报告接口
+  /report/research_report_chapter:
+    get:
+      consumes:
+      - application/json
+      description: 获取报告章节详情
+      parameters:
+      - description: Bearer 31a165baebe6dec616b1f8f3207b4273
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: 章节ID
+        in: query
+        name: research_report_type_id
+        required: true
+        type: integer
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/yb_activity.ActivityDetail'
+        "400":
+          description: 获取失败
+          schema:
+            type: string
+      security:
+      - ApiKeyAuth: []
+      summary: 获取报告章节详情
+      tags:
+      - 报告接口
   /user/apply:
     post:
       consumes:

+ 1 - 0
go.mod

@@ -25,6 +25,7 @@ require (
 	github.com/spf13/viper v1.9.0
 	github.com/swaggo/gin-swagger v1.3.3
 	github.com/swaggo/swag v1.7.4
+	github.com/tosone/minimp3 v1.0.1
 	golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
 	golang.org/x/image v0.0.0-20190802002840-cff245a6509b
 	golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 // indirect

+ 6 - 0
models/response/community.go

@@ -35,3 +35,9 @@ type CommunityReplyTotal struct {
 	Replied int `json:"replied"`
 	Total   int `json:"total"`
 }
+
+type CommunityQuestionAudioUpload struct {
+	AudioURL         string `json:"audio_url"`
+	AudioPlaySeconds string `json:"audio_play_seconds"`
+	AudioSize        string `json:"audio_size"`
+}

+ 81 - 63
models/tables/yb_community_question/entity.go

@@ -6,27 +6,33 @@ import (
 
 // YbCommunityQuestion 研报-问答社区表
 type YbCommunityQuestion struct {
-	CommunityQuestionID int       `gorm:"primaryKey;column:community_question_id;type:int(10) unsigned;not null" json:"-"`
-	UserID              int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"userId"`                                    // 提问用户ID
-	Mobile              string    `gorm:"column:mobile;type:varchar(20);not null;default:''" json:"mobile"`                                                           // 用户手机号
-	RealName            string    `gorm:"column:real_name;type:varchar(100);not null;default:''" json:"realName"`                                                     // 用户名
-	QuestionContent     string    `gorm:"column:question_content;type:varchar(255);not null;default:''" json:"questionContent"`                                       // 问题描述
-	ReplierUserID       int       `gorm:"index:idx_replier_user_id;column:replier_user_id;type:int(10) unsigned;not null;default:0" json:"replierUserId"`             // 回复人的user_id
-	ReplierAdminID      int       `gorm:"column:replier_admin_id;type:int(10) unsigned;not null;default:0" json:"replierAdminId"`                                     // 回复人关联的admin_id
-	ReplierRealName     string    `gorm:"column:replier_real_name;type:varchar(30);not null;default:''" json:"replierRealName"`                                       // 回复人姓名
-	ReplierAvatar       string    `gorm:"column:replier_avatar;type:varchar(255);not null;default:''" json:"replierAvatar"`                                           // 回复人头像
-	ReplierRank         string    `gorm:"column:replier_rank;type:varchar(100);not null;default:''" json:"replierRank"`                                               // 回复人头衔
-	DistributeAdminID   int       `gorm:"column:distribute_admin_id;type:int(10) unsigned;not null;default:0" json:"distributeAdminId"`                               // 分配人admin_id
-	ChartPermissionID   int       `gorm:"index:idx_chart_permission_id;column:chart_permission_id;type:int(10) unsigned;not null;default:0" json:"chartPermissionId"` // 关联权限ID
-	ChartPermissionName string    `gorm:"column:chart_permission_name;type:varchar(100);not null;default:''" json:"chartPermissionName"`                              // 关联权限name
-	IsRead              int       `gorm:"column:is_read;type:tinyint(4) unsigned;not null;default:0" json:"isRead"`                                                   // 用户是否已读 0-未读 1-已读
-	ReplyStatus         int       `gorm:"column:reply_status;type:tinyint(4) unsigned;not null;default:0" json:"replyStatus"`                                         // 状态 0-待分配 1-待回答 2-已回答
-	MsgSendStatus       int       `gorm:"column:msg_send_status;type:tinyint(4) unsigned;not null;default:0" json:"msgSendStatus"`                                    // 消息推送进度 0-待推送 1-已推送回答人 2-已推送提问人
-	ReplyTime           time.Time `gorm:"column:reply_time;type:datetime" json:"replyTime"`                                                                           // 回复时间
-	CreateTime          time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                               // 提问时间
-	ModifyTime          time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`                                               // 修改时间
-	IsDeleted           int       `gorm:"column:is_deleted;type:tinyint(4) unsigned;not null;default:0" json:"isDeleted"`                                             // 是否已删除 0-否 1-是
-	DeleteTime          time.Time `gorm:"column:delete_time;type:datetime" json:"deleteTime"`                                                                         // 删除时间
+	CommunityQuestionID     int       `gorm:"primaryKey;column:community_question_id;type:int(10) unsigned;not null" json:"-"`
+	UserID                  int       `gorm:"index:idx_user_id;column:user_id;type:int(10) unsigned;not null;default:0" json:"userId"`                                    // 提问用户ID
+	UserOpenid              string    `gorm:"column:user_openid;type:varchar(32);not null;default:''" json:"userOpenid"`                                                  // 提问人openid
+	Mobile                  string    `gorm:"column:mobile;type:varchar(20);not null;default:''" json:"mobile"`                                                           // 用户手机号
+	RealName                string    `gorm:"column:real_name;type:varchar(100);not null;default:''" json:"realName"`                                                     // 用户名
+	QuestionContent         string    `gorm:"column:question_content;type:varchar(255);not null;default:''" json:"questionContent"`                                       // 问题描述
+	ReplierUserID           int       `gorm:"index:idx_replier_user_id;column:replier_user_id;type:int(10) unsigned;not null;default:0" json:"replierUserId"`             // 回复人的user_id
+	ReplierOpenid           string    `gorm:"column:replier_openid;type:varchar(32);not null;default:''" json:"replierOpenid"`                                            // 回复人openid
+	ReplierAdminID          int       `gorm:"column:replier_admin_id;type:int(10) unsigned;not null;default:0" json:"replierAdminId"`                                     // 回复人关联的admin_id
+	ReplierRealName         string    `gorm:"column:replier_real_name;type:varchar(30);not null;default:''" json:"replierRealName"`                                       // 回复人姓名
+	ReplierAvatar           string    `gorm:"column:replier_avatar;type:varchar(255);not null;default:''" json:"replierAvatar"`                                           // 回复人头像
+	ResearchGroupFirstID    int       `gorm:"column:research_group_first_id;type:int(10) unsigned;not null;default:0" json:"researchGroupFirstId"`                        // 回复人研究方向一级分组ID
+	ResearchGroupSecondID   int       `gorm:"column:research_group_second_id;type:int(10) unsigned;not null;default:0" json:"researchGroupSecondId"`                      // 回复人研究方向二级分组ID
+	ResearchGroupFirstName  string    `gorm:"column:research_group_first_name;type:varchar(100);not null;default:''" json:"researchGroupFirstName"`                       // 研究方向一级分组名称
+	ResearchGroupSecondName string    `gorm:"column:research_group_second_name;type:varchar(100);not null;default:''" json:"researchGroupSecondName"`                     // 研究方向二级分组名称
+	DistributeAdminID       int       `gorm:"column:distribute_admin_id;type:int(10) unsigned;not null;default:0" json:"distributeAdminId"`                               // 分配人admin_id
+	DistributeTime          time.Time `gorm:"column:distribute_time;type:datetime" json:"distributeTime"`                                                                 // 分配时间
+	ChartPermissionID       int       `gorm:"index:idx_chart_permission_id;column:chart_permission_id;type:int(10) unsigned;not null;default:0" json:"chartPermissionId"` // 关联权限ID
+	ChartPermissionName     string    `gorm:"column:chart_permission_name;type:varchar(100);not null;default:''" json:"chartPermissionName"`                              // 关联权限name
+	IsRead                  int       `gorm:"column:is_read;type:tinyint(4) unsigned;not null;default:0" json:"isRead"`                                                   // 用户是否已读 0-未读 1-已读
+	ReplyStatus             int       `gorm:"column:reply_status;type:tinyint(4) unsigned;not null;default:0" json:"replyStatus"`                                         // 回复状态 1-待分配 2-待回答 3-已回答
+	MsgSendStatus           int       `gorm:"column:msg_send_status;type:tinyint(4) unsigned;not null;default:0" json:"msgSendStatus"`                                    // 消息推送进度 0-待推送 1-已推送回答人 2-已推送提问人
+	ReplyTime               time.Time `gorm:"column:reply_time;type:datetime" json:"replyTime"`                                                                           // 回复时间
+	CreateTime              time.Time `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP" json:"createTime"`                                               // 提问时间
+	ModifyTime              time.Time `gorm:"column:modify_time;type:datetime;default:CURRENT_TIMESTAMP" json:"modifyTime"`                                               // 修改时间
+	IsDeleted               int       `gorm:"column:is_deleted;type:tinyint(4) unsigned;not null;default:0" json:"isDeleted"`                                             // 是否已删除 0-否 1-是
+	DeleteTime              time.Time `gorm:"column:delete_time;type:datetime" json:"deleteTime"`                                                                         // 删除时间
 }
 
 // TableName get sql table name.获取数据库表名
@@ -36,47 +42,59 @@ func (m *YbCommunityQuestion) TableName() string {
 
 // YbCommunityQuestionColumns get sql column name.获取数据库列名
 var YbCommunityQuestionColumns = struct {
-	CommunityQuestionID string
-	UserID              string
-	Mobile              string
-	RealName            string
-	QuestionContent     string
-	ReplierUserID       string
-	ReplierAdminID      string
-	ReplierRealName     string
-	ReplierAvatar       string
-	ReplierRank         string
-	DistributeAdminID   string
-	ChartPermissionID   string
-	ChartPermissionName string
-	IsRead              string
-	ReplyStatus         string
-	MsgSendStatus       string
-	ReplyTime           string
-	CreateTime          string
-	ModifyTime          string
-	IsDeleted           string
-	DeleteTime          string
+	CommunityQuestionID     string
+	UserID                  string
+	UserOpenid              string
+	Mobile                  string
+	RealName                string
+	QuestionContent         string
+	ReplierUserID           string
+	ReplierOpenid           string
+	ReplierAdminID          string
+	ReplierRealName         string
+	ReplierAvatar           string
+	ResearchGroupFirstID    string
+	ResearchGroupSecondID   string
+	ResearchGroupFirstName  string
+	ResearchGroupSecondName string
+	DistributeAdminID       string
+	DistributeTime          string
+	ChartPermissionID       string
+	ChartPermissionName     string
+	IsRead                  string
+	ReplyStatus             string
+	MsgSendStatus           string
+	ReplyTime               string
+	CreateTime              string
+	ModifyTime              string
+	IsDeleted               string
+	DeleteTime              string
 }{
-	CommunityQuestionID: "community_question_id",
-	UserID:              "user_id",
-	Mobile:              "mobile",
-	RealName:            "real_name",
-	QuestionContent:     "question_content",
-	ReplierUserID:       "replier_user_id",
-	ReplierAdminID:      "replier_admin_id",
-	ReplierRealName:     "replier_real_name",
-	ReplierAvatar:       "replier_avatar",
-	ReplierRank:         "replier_rank",
-	DistributeAdminID:   "distribute_admin_id",
-	ChartPermissionID:   "chart_permission_id",
-	ChartPermissionName: "chart_permission_name",
-	IsRead:              "is_read",
-	ReplyStatus:         "reply_status",
-	MsgSendStatus:       "msg_send_status",
-	ReplyTime:           "reply_time",
-	CreateTime:          "create_time",
-	ModifyTime:          "modify_time",
-	IsDeleted:           "is_deleted",
-	DeleteTime:          "delete_time",
+	CommunityQuestionID:     "community_question_id",
+	UserID:                  "user_id",
+	UserOpenid:              "user_openid",
+	Mobile:                  "mobile",
+	RealName:                "real_name",
+	QuestionContent:         "question_content",
+	ReplierUserID:           "replier_user_id",
+	ReplierOpenid:           "replier_openid",
+	ReplierAdminID:          "replier_admin_id",
+	ReplierRealName:         "replier_real_name",
+	ReplierAvatar:           "replier_avatar",
+	ResearchGroupFirstID:    "research_group_first_id",
+	ResearchGroupSecondID:   "research_group_second_id",
+	ResearchGroupFirstName:  "research_group_first_name",
+	ResearchGroupSecondName: "research_group_second_name",
+	DistributeAdminID:       "distribute_admin_id",
+	DistributeTime:          "distribute_time",
+	ChartPermissionID:       "chart_permission_id",
+	ChartPermissionName:     "chart_permission_name",
+	IsRead:                  "is_read",
+	ReplyStatus:             "reply_status",
+	MsgSendStatus:           "msg_send_status",
+	ReplyTime:               "reply_time",
+	CreateTime:              "create_time",
+	ModifyTime:              "modify_time",
+	IsDeleted:               "is_deleted",
+	DeleteTime:              "delete_time",
 }

+ 5 - 4
routers/community.go

@@ -10,8 +10,9 @@ func InitCommunity(r *gin.Engine)  {
 	rGroup := r.Group("api/community").Use(middleware.Token())
 	rGroup.GET("/question/list", community.QuestionList)
 	rGroup.GET("/question/detail", community.QuestionDetail)
-	rGroup.GET("/question/ask", community.AskQuestion)
-	rGroup.GET("/question/reply/publish", community.ReplyQuestion)
-	rGroup.GET("/question/read", community.ReadReply)
-	rGroup.GET("/question/reply/list_total", community.ReplyListTotal)
+	rGroup.POST("/question/ask", community.QuestionAsk)
+	rGroup.POST("/question/reply", community.QuestionReply)
+	rGroup.POST("/question/reply/read", community.QuestionReplyRead)
+	rGroup.GET("/question/reply/total", community.QuestionReplyTotal)
+	rGroup.POST("/question/reply/upload_audio", community.QuestionUploadAudio)
 }

+ 21 - 4
services/community/question.go

@@ -15,6 +15,7 @@ import (
 	"time"
 )
 
+// GetQuestionList 获取问答列表
 func GetQuestionList(pageIndex, pageSize, onlyMine, chartPermissionId, replyStatus, replierUserId int, userInfo user.UserInfo) (resp *response.CommunityQuestionList, err error) {
 	condition := make(map[string]interface{})
 	condition["is_deleted ="] = 0
@@ -94,12 +95,13 @@ func GetQuestionList(pageIndex, pageSize, onlyMine, chartPermissionId, replyStat
 				})
 			}
 		}
+		replierRank := fmt.Sprintf("弘则%s研究员", v.ResearchGroupFirstName)
 		item := &response.CommunityQuestionItem{
 			CommunityQuestionID: v.CommunityQuestionID,
 			UserId:              v.UserID,
 			QuestionContent:     v.QuestionContent,
 			ReplierRealName:     v.ReplierRealName,
-			ReplierRank:         v.ReplierRank,
+			ReplierRank:         replierRank,
 			ReplierAvatar:       v.ReplierAvatar,
 			ChartPermissionID:   v.CommunityQuestionID,
 			ChartPermissionName: v.ChartPermissionName,
@@ -119,6 +121,7 @@ func GetQuestionList(pageIndex, pageSize, onlyMine, chartPermissionId, replyStat
 	return
 }
 
+// GetQuestionDetail 获取问答详情
 func GetQuestionDetail(questionId int) (item *response.CommunityQuestionItem, err error) {
 	detail, e := yb_community_question.GetItemById(questionId)
 	if e != nil {
@@ -140,12 +143,13 @@ func GetQuestionDetail(questionId int) (item *response.CommunityQuestionItem, er
 			Sort:                a.Sort,
 		})
 	}
+	replierRank := fmt.Sprintf("弘则%s研究员", detail.ResearchGroupFirstName)
 	item = &response.CommunityQuestionItem{
 		CommunityQuestionID: detail.CommunityQuestionID,
 		UserId:              detail.UserID,
 		QuestionContent:     detail.QuestionContent,
 		ReplierRealName:     detail.ReplierRealName,
-		ReplierRank:         detail.ReplierRank,
+		ReplierRank:         replierRank,
 		ReplierAvatar:       detail.ReplierAvatar,
 		ChartPermissionID:   detail.CommunityQuestionID,
 		ChartPermissionName: detail.ChartPermissionName,
@@ -157,9 +161,11 @@ func GetQuestionDetail(questionId int) (item *response.CommunityQuestionItem, er
 	return
 }
 
-func CreateQuestion(userId int, mobile, realName, content string) (err error) {
+// CreateQuestion 新增问答
+func CreateQuestion(userId int, mobile, openid, realName, content string) (err error) {
 	item := &yb_community_question.YbCommunityQuestion{
 		UserID:          userId,
+		UserOpenid:      openid,
 		Mobile:          mobile,
 		RealName:        realName,
 		QuestionContent: content,
@@ -171,6 +177,7 @@ func CreateQuestion(userId int, mobile, realName, content string) (err error) {
 	return
 }
 
+// ReplyUserQuestion 回复问题
 func ReplyUserQuestion(replierId, questionId int, audios []*request.ReplyReqAudioList) (err error) {
 	item, e := yb_community_question.GetItemById(questionId)
 	if e != nil {
@@ -208,10 +215,14 @@ func ReplyUserQuestion(replierId, questionId int, audios []*request.ReplyReqAudi
 		err = errors.New("UpdateQuestionAndAudioList Err:" + e.Error())
 		return
 	}
-	// TODO:推送回复模板消息给提问人
+	// 推送回复消息给用户
+	go func() {
+		_ = sendReplyMsg2User()
+	}()
 	return
 }
 
+// ReadQuestionReply 回复已读
 func ReadQuestionReply(userId int, questionId int) (err error) {
 	item, e := yb_community_question.GetItemById(questionId)
 	if e != nil {
@@ -233,6 +244,7 @@ func ReadQuestionReply(userId int, questionId int) (err error) {
 	return
 }
 
+// GetReplyListTotal 获取问答列表数量统计
 func GetReplyListTotal(replierUserId int) (resp *response.CommunityReplyTotal, err error) {
 	countList, e := yb_community_question.GetReplierQuestionCount(replierUserId)
 	if e != nil {
@@ -252,3 +264,8 @@ func GetReplyListTotal(replierUserId int) (resp *response.CommunityReplyTotal, e
 	resp.Total = resp.Wait + resp.Replied
 	return
 }
+
+// sendReply2User 推送模板消息给用户
+func sendReplyMsg2User() (err error) {
+	return
+}

+ 16 - 0
services/media.go

@@ -0,0 +1,16 @@
+package services
+
+import (
+	"github.com/tosone/minimp3"
+)
+
+// GetMP3PlayDuration 获取MP3的时长
+func GetMP3PlayDuration(mp3Data []byte) (seconds int, err error) {
+	dec, _, err := minimp3.DecodeFull(mp3Data)
+	if err != nil {
+		return 0, err
+	}
+	// 音乐时长 = (文件大小(byte) - 128(ID3信息)) * 8(to bit) / (码率(kbps b:bit) * 1000)(kilo bit to bit)
+	seconds = (len(mp3Data) - 128) * 8 / (dec.Kbps * 1000)
+	return seconds, nil
+}

+ 8 - 9
services/oss.go

@@ -89,14 +89,13 @@ func UploadVideoAliyun(filename, filepath, savePath string) error {
 	return err
 }
 
-
 var (
-	Bucketname       string = "hzchart"
-	Endpoint         string = "oss-cn-shanghai.aliyuncs.com"
-	Imghost          string = "https://hzstatic.hzinsights.com/"
-	UploadDir		 string = "static/images/"
-	AccessKeyId      string = "LTAIFMZYQhS2BTvW"
-	AccessKeySecret  string = "12kk1ptCHoGWedhBnKRVW5hRJzq9Fq"
+	Bucketname      string = "hzchart"
+	Endpoint        string = "oss-cn-shanghai.aliyuncs.com"
+	ResourceHost    string = "https://hzstatic.hzinsights.com/"
+	StaticDir       string = "static/"
+	AccessKeyId     string = "LTAIFMZYQhS2BTvW"
+	AccessKeySecret string = "12kk1ptCHoGWedhBnKRVW5hRJzq9Fq"
 )
 
 // UploadAliyunToDir
@@ -112,12 +111,12 @@ func UploadAliyunToDir(filename, filepath, fileDir string) (string, error) {
 	if fileDir == "" {
 		fileDir = time.Now().Format("200601/20060102/")
 	}
-	path := UploadDir + fileDir
+	path := StaticDir + fileDir
 	path += filename
 	err = bucket.PutObjectFromFile(path, filepath)
 	if err != nil {
 		return "3", err
 	}
-	path = Imghost + path
+	path = ResourceHost + path
 	return path, err
 }

+ 1 - 1
services/share_poster.go

@@ -215,7 +215,7 @@ func CreateAndUploadSunCode(page, scene, version string) (imgUrl string, err err
 		os.Remove(fpath)
 	}()
 	// 上传OSS
-	fileDir := "yb/suncode/"
+	fileDir := "images/yb/suncode/"
 	imgUrl, err = UploadAliyunToDir(fileName, fpath, fileDir)
 	if err != nil {
 		return

+ 7 - 0
utils/common.go

@@ -960,3 +960,10 @@ func InArray(needle interface{}, hyStack interface{}) bool {
 	}
 	return false
 }
+
+// bit转MB 保留小数
+func Bit2MB(bitSize int64, prec int) (size float64) {
+	mb := float64(bitSize)/float64(1024*1024)
+	size, _ = strconv.ParseFloat(strconv.FormatFloat(mb,'f',prec,64), 64)
+	return
+}

Some files were not shown because too many files changed in this diff