diff --git a/api/core/app_server.go b/api/core/app_server.go index d7bf5590..84c38cb4 100644 --- a/api/core/app_server.go +++ b/api/core/app_server.go @@ -155,7 +155,6 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc { c.Request.URL.Path == "/api/mj/notify" || c.Request.URL.Path == "/api/invite/hits" || c.Request.URL.Path == "/api/sd/jobs" || - c.Request.URL.Path == "/api/upload" || strings.HasPrefix(c.Request.URL.Path, "/api/test") || strings.HasPrefix(c.Request.URL.Path, "/api/function/") || strings.HasPrefix(c.Request.URL.Path, "/api/sms/") || diff --git a/api/handler/upload_handler.go b/api/handler/upload_handler.go index 62f508a3..6a3da8a4 100644 --- a/api/handler/upload_handler.go +++ b/api/handler/upload_handler.go @@ -3,9 +3,13 @@ package handler import ( "chatplus/core" "chatplus/service/oss" + "chatplus/store/model" + "chatplus/store/vo" + "chatplus/utils" "chatplus/utils/resp" "github.com/gin-gonic/gin" "gorm.io/gorm" + "time" ) type UploadHandler struct { @@ -27,5 +31,40 @@ func (h *UploadHandler) Upload(c *gin.Context) { return } + userId := h.GetLoginUserId(c) + res := h.db.Create(&model.File{ + UserId: userId, + Name: file.Name, + URL: file.URL, + Ext: file.Ext, + Size: file.Size, + CreatedAt: time.Time{}, + }) + if res.Error != nil || res.RowsAffected == 0 { + resp.ERROR(c, "error with update database: "+res.Error.Error()) + return + } + resp.SUCCESS(c, file) } + +func (h *UploadHandler) List(c *gin.Context) { + userId := h.GetLoginUserId(c) + var items []model.File + var files = make([]vo.File, 0) + h.db.Debug().Where("user_id = ?", userId).Find(&items) + if len(items) > 0 { + for _, v := range items { + var file vo.File + err := utils.CopyObject(v, &file) + if err != nil { + logger.Error(err) + continue + } + file.CreatedAt = v.CreatedAt.Unix() + files = append(files, file) + } + } + + resp.SUCCESS(c, files) +} diff --git a/api/main.go b/api/main.go index e4984dbc..514d3e19 100644 --- a/api/main.go +++ b/api/main.go @@ -214,6 +214,7 @@ func main() { }), fx.Invoke(func(s *core.AppServer, h *handler.UploadHandler) { s.Engine.POST("/api/upload", h.Upload) + s.Engine.GET("/api/upload/list", h.List) }), fx.Invoke(func(s *core.AppServer, h *handler.SmsHandler) { group := s.Engine.Group("/api/sms/") diff --git a/api/service/oss/aliyun_oss.go b/api/service/oss/aliyun_oss.go index 35ea314d..c9f4ea21 100644 --- a/api/service/oss/aliyun_oss.go +++ b/api/service/oss/aliyun_oss.go @@ -66,6 +66,7 @@ func (s AliYunOss) PutFile(ctx *gin.Context, name string) (File, error) { } return File{ + Name: file.Filename, URL: fmt.Sprintf("%s/%s", s.config.Domain, objectKey), Ext: fileExt, Size: file.Size, diff --git a/api/service/oss/localstorage.go b/api/service/oss/localstorage.go index 7536dab3..0ce5be2d 100644 --- a/api/service/oss/localstorage.go +++ b/api/service/oss/localstorage.go @@ -41,6 +41,7 @@ func (s LocalStorage) PutFile(ctx *gin.Context, name string) (File, error) { ext := filepath.Ext(file.Filename) return File{ + Name: file.Filename, URL: utils.GenUploadUrl(s.config.BasePath, s.config.BaseURL, path), Ext: ext, Size: file.Size, diff --git a/api/service/oss/minio_oss.go b/api/service/oss/minio_oss.go index d9e16e47..94b03a24 100644 --- a/api/service/oss/minio_oss.go +++ b/api/service/oss/minio_oss.go @@ -87,6 +87,7 @@ func (s MiniOss) PutFile(ctx *gin.Context, name string) (File, error) { } return File{ + Name: file.Filename, URL: fmt.Sprintf("%s/%s/%s", s.config.Domain, s.config.Bucket, info.Key), Ext: fileExt, Size: file.Size, diff --git a/api/service/oss/qiniu_oss.go b/api/service/oss/qiniu_oss.go index cf7789d1..3b989308 100644 --- a/api/service/oss/qiniu_oss.go +++ b/api/service/oss/qiniu_oss.go @@ -74,6 +74,7 @@ func (s QinNiuOss) PutFile(ctx *gin.Context, name string) (File, error) { } return File{ + Name: file.Filename, URL: fmt.Sprintf("%s/%s", s.config.Domain, ret.Key), Ext: fileExt, Size: file.Size, diff --git a/api/service/oss/uploader.go b/api/service/oss/uploader.go index 0861e09a..a8f7b50c 100644 --- a/api/service/oss/uploader.go +++ b/api/service/oss/uploader.go @@ -3,9 +3,10 @@ package oss import "github.com/gin-gonic/gin" type File struct { - Size int64 - URL string - Ext string + Name string `json:"name"` + Size int64 `json:"size"` + URL string `json:"url"` + Ext string `json:"ext"` } type Uploader interface { PutFile(ctx *gin.Context, name string) (File, error) diff --git a/api/store/model/file.go b/api/store/model/file.go index 24ed0d06..dafd650e 100644 --- a/api/store/model/file.go +++ b/api/store/model/file.go @@ -5,6 +5,7 @@ import "time" type File struct { Id uint `gorm:"primarykey;column:id"` UserId uint + Name string URL string Ext string Size int64 diff --git a/api/store/vo/File.go b/api/store/vo/file.go similarity index 87% rename from api/store/vo/File.go rename to api/store/vo/file.go index 1127bd6b..2a0ebc6b 100644 --- a/api/store/vo/File.go +++ b/api/store/vo/file.go @@ -3,6 +3,7 @@ package vo type File struct { Id uint UserId uint `json:"user_id"` + Name string `json:"name"` URL string `json:"url"` Ext string `json:"ext"` Size int64 `json:"size"` diff --git a/database/update-v3.2.5.sql b/database/update-v3.2.5.sql index 5c80c025..7815dded 100644 --- a/database/update-v3.2.5.sql +++ b/database/update-v3.2.5.sql @@ -9,4 +9,5 @@ CREATE TABLE `chatgpt_plus`.`chatgpt_files` ( `created_at` DATETIME NOT NULL COMMENT '创建时间' , PRIMARY KEY (`id`)) ENGINE = InnoDB COMMENT = '用户文件表'; -ALTER TABLE `chatgpt_files` ADD `size` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '文件大小' AFTER `ext`; \ No newline at end of file +ALTER TABLE `chatgpt_files` ADD `size` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '文件大小' AFTER `ext`; +ALTER TABLE `chatgpt_files` ADD `name` VARCHAR(100) NOT NULL COMMENT '文件名' AFTER `user_id`; \ No newline at end of file diff --git a/web/public/images/ext/doc.png b/web/public/images/ext/doc.png new file mode 100644 index 00000000..9e2c3696 Binary files /dev/null and b/web/public/images/ext/doc.png differ diff --git a/web/public/images/ext/file.png b/web/public/images/ext/file.png new file mode 100644 index 00000000..45652525 Binary files /dev/null and b/web/public/images/ext/file.png differ diff --git a/web/public/images/ext/md.png b/web/public/images/ext/md.png new file mode 100644 index 00000000..c8d32228 Binary files /dev/null and b/web/public/images/ext/md.png differ diff --git a/web/public/images/ext/pdf.png b/web/public/images/ext/pdf.png new file mode 100644 index 00000000..4987837c Binary files /dev/null and b/web/public/images/ext/pdf.png differ diff --git a/web/public/images/ext/ppt.png b/web/public/images/ext/ppt.png new file mode 100644 index 00000000..44019095 Binary files /dev/null and b/web/public/images/ext/ppt.png differ diff --git a/web/public/images/ext/sql.png b/web/public/images/ext/sql.png new file mode 100644 index 00000000..c2255c8c Binary files /dev/null and b/web/public/images/ext/sql.png differ diff --git a/web/public/images/ext/txt.png b/web/public/images/ext/txt.png new file mode 100644 index 00000000..11744f48 Binary files /dev/null and b/web/public/images/ext/txt.png differ diff --git a/web/public/images/ext/xls.png b/web/public/images/ext/xls.png new file mode 100644 index 00000000..1897bdc3 Binary files /dev/null and b/web/public/images/ext/xls.png differ diff --git a/web/src/assets/css/chat-plus.css b/web/src/assets/css/chat-plus.css index 5e07cdd9..f7d03f65 100644 --- a/web/src/assets/css/chat-plus.css +++ b/web/src/assets/css/chat-plus.css @@ -213,6 +213,11 @@ width: 0; height: 0; } +#app .common-layout .el-main .right-box #container .input-box .input-container .select-file { + position: absolute; + right: 48px; + top: 20px; +} #app .common-layout .el-main .right-box #container .input-box .input-container .send-btn { position: absolute; right: 12px; diff --git a/web/src/assets/css/chat-plus.styl b/web/src/assets/css/chat-plus.styl index fe6c2b84..3a628f31 100644 --- a/web/src/assets/css/chat-plus.styl +++ b/web/src/assets/css/chat-plus.styl @@ -279,6 +279,12 @@ $borderColor = #4676d0; } } + .select-file { + position absolute; + right 48px; + top 20px; + } + .send-btn { position absolute; right 12px; diff --git a/web/src/assets/iconfont/iconfont.css b/web/src/assets/iconfont/iconfont.css index a16a9c4e..3dece43a 100644 --- a/web/src/assets/iconfont/iconfont.css +++ b/web/src/assets/iconfont/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 4125778 */ - src: url('iconfont.woff2?t=1703124384910') format('woff2'), - url('iconfont.woff?t=1703124384910') format('woff'), - url('iconfont.ttf?t=1703124384910') format('truetype'); + src: url('iconfont.woff2?t=1705313263366') format('woff2'), + url('iconfont.woff?t=1705313263366') format('woff'), + url('iconfont.ttf?t=1705313263366') format('truetype'); } .iconfont { @@ -13,6 +13,38 @@ -moz-osx-font-smoothing: grayscale; } +.icon-xls:before { + content: "\e678"; +} + +.icon-file:before { + content: "\e62f"; +} + +.icon-doc:before { + content: "\e6c2"; +} + +.icon-pdf:before { + content: "\e6c3"; +} + +.icon-ppt:before { + content: "\e642"; +} + +.icon-txt:before { + content: "\e644"; +} + +.icon-sql:before { + content: "\e65b"; +} + +.icon-md:before { + content: "\e63a"; +} + .icon-loading:before { content: "\e627"; } diff --git a/web/src/assets/iconfont/iconfont.js b/web/src/assets/iconfont/iconfont.js index 6521c8f0..36dd6b72 100644 --- a/web/src/assets/iconfont/iconfont.js +++ b/web/src/assets/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4125778='',function(a){var l=(l=document.getElementsByTagName("script"))[l.length-1],c=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,o,i,h,e,s=function(l,c){c.parentNode.insertBefore(l,c)};if(c&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}t=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?s(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),t()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(i=t,h=a.document,e=!1,z(),h.onreadystatechange=function(){"complete"==h.readyState&&(h.onreadystatechange=null,m())})}function m(){e||(e=!0,i())}function z(){try{h.documentElement.doScroll("left")}catch(l){return void setTimeout(z,50)}m()}}(window); \ No newline at end of file +window._iconfont_svg_string_4125778='',function(a){var l=(l=document.getElementsByTagName("script"))[l.length-1],c=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,h,i,o,z,v=function(l,c){c.parentNode.insertBefore(l,c)};if(c&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}t=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?v(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),t()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(i=t,o=a.document,z=!1,e(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,m())})}function m(){z||(z=!0,i())}function e(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(e,50)}m()}}(window); \ No newline at end of file diff --git a/web/src/assets/iconfont/iconfont.json b/web/src/assets/iconfont/iconfont.json index ea413f94..50942272 100644 --- a/web/src/assets/iconfont/iconfont.json +++ b/web/src/assets/iconfont/iconfont.json @@ -5,6 +5,62 @@ "css_prefix_text": "icon-", "description": "", "glyphs": [ + { + "icon_id": "12600976", + "name": "xls", + "font_class": "xls", + "unicode": "e678", + "unicode_decimal": 59000 + }, + { + "icon_id": "3750429", + "name": "file", + "font_class": "file", + "unicode": "e62f", + "unicode_decimal": 58927 + }, + { + "icon_id": "4318810", + "name": "doc", + "font_class": "doc", + "unicode": "e6c2", + "unicode_decimal": 59074 + }, + { + "icon_id": "4318811", + "name": "pdf", + "font_class": "pdf", + "unicode": "e6c3", + "unicode_decimal": 59075 + }, + { + "icon_id": "4628503", + "name": "ppt", + "font_class": "ppt", + "unicode": "e642", + "unicode_decimal": 58946 + }, + { + "icon_id": "6233095", + "name": "txt", + "font_class": "txt", + "unicode": "e644", + "unicode_decimal": 58948 + }, + { + "icon_id": "12600910", + "name": "sql", + "font_class": "sql", + "unicode": "e65b", + "unicode_decimal": 58971 + }, + { + "icon_id": "31260974", + "name": "md", + "font_class": "md", + "unicode": "e63a", + "unicode_decimal": 58938 + }, { "icon_id": "1278349", "name": "loading", diff --git a/web/src/assets/iconfont/iconfont.ttf b/web/src/assets/iconfont/iconfont.ttf index 70c1c350..a00e66a7 100644 Binary files a/web/src/assets/iconfont/iconfont.ttf and b/web/src/assets/iconfont/iconfont.ttf differ diff --git a/web/src/assets/iconfont/iconfont.woff b/web/src/assets/iconfont/iconfont.woff index bba70a0d..0eb4791e 100644 Binary files a/web/src/assets/iconfont/iconfont.woff and b/web/src/assets/iconfont/iconfont.woff differ diff --git a/web/src/assets/iconfont/iconfont.woff2 b/web/src/assets/iconfont/iconfont.woff2 index 5264eadc..1d906e0c 100644 Binary files a/web/src/assets/iconfont/iconfont.woff2 and b/web/src/assets/iconfont/iconfont.woff2 differ diff --git a/web/src/components/FileSelect.vue b/web/src/components/FileSelect.vue new file mode 100644 index 00000000..e25c7de5 --- /dev/null +++ b/web/src/components/FileSelect.vue @@ -0,0 +1,171 @@ + + + + + \ No newline at end of file diff --git a/web/src/components/UserProfile.vue b/web/src/components/UserProfile.vue index 105fd0b6..1d16ae84 100644 --- a/web/src/components/UserProfile.vue +++ b/web/src/components/UserProfile.vue @@ -7,6 +7,7 @@ :auto-upload="true" :show-file-list="false" :http-request="afterRead" + accept=".png,.jpg,.jpeg,.bmp" > diff --git a/web/src/views/ChatPlus.vue b/web/src/views/ChatPlus.vue index 8611acc8..b45e9a32 100644 --- a/web/src/views/ChatPlus.vue +++ b/web/src/views/ChatPlus.vue @@ -187,6 +187,9 @@ :rows="2" placeholder="按 Enter 键发送消息,使用 Ctrl + Enter 换行" /> + + + @@ -290,6 +293,7 @@ import ConfigDialog from "@/components/ConfigDialog.vue"; import {checkSession} from "@/action/session"; import Welcome from "@/components/Welcome.vue"; import ChatMidJourney from "@/components/ChatMidJourney.vue"; +import FileSelect from "@/components/FileSelect.vue"; const title = ref('ChatGPT-智能助手'); const models = ref([]) @@ -875,6 +879,11 @@ const notShow = () => { localStorage.setItem(showNoticeKey.value + loginUser.value.username, true) showDemoNotice.value = false } + +// 插入文件路径 +const insertURL = (url) => { + prompt.value += " " + url + " " +}