diff --git a/devcloud/audit/audit/sender.go b/devcloud/audit/audit/sender.go index 19eb689..0a45215 100644 --- a/devcloud/audit/audit/sender.go +++ b/devcloud/audit/audit/sender.go @@ -14,41 +14,43 @@ import ( func (a *EventSender) SendEvent() restful.FilterFunction { return func(req *restful.Request, resp *restful.Response, fc *restful.FilterChain) { sr := req.SelectedRoute() - md := NewMetaData(sr.Metadata()) + if sr != nil { + md := NewMetaData(sr.Metadata()) - // 开关打开,则开启审计 - if md.GetBool(META_AUDIT_KEY) { + // 开关打开,则开启审计 + if md.GetBool(META_AUDIT_KEY) { - // 获取当前是否需要审计 - e := event.NewEvent() + // 获取当前是否需要审计 + e := event.NewEvent() - // 用户信息 - tk := token.GetTokenFromCtx(req.Request.Context()) - if tk != nil { - e.Who = tk.UserName - e.Namespace = tk.NamespaceName - } + // 用户信息 + tk := token.GetTokenFromCtx(req.Request.Context()) + if tk != nil { + e.Who = tk.UserName + e.Namespace = tk.NamespaceName + } - // ioc 里面获取当前应用的名称 - e.Service = application.Get().AppName - e.ResourceType = md.GetString(endpoint.META_RESOURCE_KEY) - e.Action = md.GetString(endpoint.META_ACTION_KEY) + // ioc 里面获取当前应用的名称 + e.Service = application.Get().AppName + e.ResourceType = md.GetString(endpoint.META_RESOURCE_KEY) + e.Action = md.GetString(endpoint.META_ACTION_KEY) - // {id} /:id - e.ResourceId = req.PathParameter("id") - e.UserAgent = req.Request.UserAgent() - e.Extras["method"] = sr.Method() - e.Extras["path"] = sr.Path() - e.Extras["operation"] = sr.Operation() + // {id} /:id + e.ResourceId = req.PathParameter("id") + e.UserAgent = req.Request.UserAgent() + e.Extras["method"] = sr.Method() + e.Extras["path"] = sr.Path() + e.Extras["operation"] = sr.Operation() - // 补充处理后的数据 - e.StatusCode = resp.StatusCode() - // 发送给topic, 使用这个中间件的使用者,需要配置kafka - err := a.wirter.WriteMessages(context.Background(), e.ToKafkaMessage()) - if err != nil { - a.log.Error().Msgf("send message error, %s", err) - } else { - a.log.Debug().Msgf("send audit event ok, who: %s, resource: %s, action: %s", e.Who, e.ResourceType, e.Action) + // 补充处理后的数据 + e.StatusCode = resp.StatusCode() + // 发送给topic, 使用这个中间件的使用者,需要配置kafka + err := a.wirter.WriteMessages(context.Background(), e.ToKafkaMessage()) + if err != nil { + a.log.Error().Msgf("send message error, %s", err) + } else { + a.log.Debug().Msgf("send audit event ok, who: %s, resource: %s, action: %s", e.Who, e.ResourceType, e.Action) + } } } diff --git a/devcloud/mcenter/permission/checker.go b/devcloud/mcenter/permission/checker.go index 1d6c63a..9bd3180 100644 --- a/devcloud/mcenter/permission/checker.go +++ b/devcloud/mcenter/permission/checker.go @@ -78,28 +78,31 @@ func (c *Checker) Check(r *restful.Request, w *restful.Response, next *restful.F // 1. 知道用户当前访问的是哪个接口, 当前url 匹配到的路由是哪个 // SelectedRoute, 它可以返回当前URL适配哪个路有, RouteReader // 封装了一个函数 来获取Meta信息 NewEntryFromRestRouteReader - route := endpoint.NewEntryFromRestRouteReader(r.SelectedRoute()) - if route.RequiredAuth { - // 校验身份 - tk, err := c.CheckToken(r) - if err != nil { - response.Failed(w, err) - return + sr := r.SelectedRoute() + if sr != nil { + route := endpoint.NewEntryFromRestRouteReader(sr) + if route.RequiredAuth { + // 校验身份 + tk, err := c.CheckToken(r) + if err != nil { + response.Failed(w, err) + return + } + + // 校验权限 + if err := c.CheckPolicy(r, tk, route); err != nil { + response.Failed(w, err) + return + } + + // 如果校验成功,需要把 用户的身份信息,放到请求的上下文中,方便后面的逻辑获取 + // context.WithValue 来往ctx 添加 value + // key: value, value token对象 + ctx := context.WithValue(r.Request.Context(), token.CTX_TOKEN_KEY, tk) + + // ctx 生成一个新的,继续往下传递 + r.Request = r.Request.WithContext(ctx) } - - // 校验权限 - if err := c.CheckPolicy(r, tk, route); err != nil { - response.Failed(w, err) - return - } - - // 如果校验成功,需要把 用户的身份信息,放到请求的上下文中,方便后面的逻辑获取 - // context.WithValue 来往ctx 添加 value - // key: value, value token对象 - ctx := context.WithValue(r.Request.Context(), token.CTX_TOKEN_KEY, tk) - - // ctx 生成一个新的,继续往下传递 - r.Request = r.Request.WithContext(ctx) } // 请求处理 diff --git a/devcloud/web/docs/README.md b/devcloud/web/docs/README.md index b5e7e3e..1da68cc 100644 --- a/devcloud/web/docs/README.md +++ b/devcloud/web/docs/README.md @@ -22,10 +22,196 @@ import '@arco-design/web-vue/dist/arco.css' app.use(ArcoVue) ``` +## ajax + +如何将表单数据 提交给服务器, 封装的比较友好的js的http客户端, [axios](https://axios-http.com/docs/intro) + +```sh +import axios from 'axios' + +// 封装一个axios的实例,http cient实例 +// https://axios-http.com/zh/docs/instance +const client = axios.create({ + baseURL: 'http://127.0.0.1:8080', + timeout: 3000, +}) + +export default client +``` + +基于客户端封装的mcenter client + +```sh +import client from './client' + +var API = { + Login: (data) => { + return client.post('/api/devcloud/v1/token', data) + }, +} + +export default API +``` + +## 配置vite代理开发 + +```js +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue(), vueDevTools()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + server: { + proxy: { + '/api': 'http://127.0.0.1:8080', + }, + }, +}) +``` + +去掉baseURL,应用使用代理 + +```js +// 封装一个axios的实例,http cient实例 +// https://axios-http.com/zh/docs/instance +const client = axios.create({ + timeout: 3000, +}) +``` + +## 统一处理 API的 异常 + +设置axios的中间件, 统一识别并处理报错 + +```js +// 拦截API的返回结果, 如果是异常 提取异常信息,并展示 +// 如果正常 则直接返回 API的响应结果 +// https://axios-http.com/zh/docs/interceptors +client.interceptors.response.use( + (data) => { + return data.data + }, + (error) => { + // 提取错误 + var msg = error.message + + // 如果有更加详细的信息 + if (error.response.data.message) { + msg = error.response.data.message + } + + Message.error(msg) + return error + }, +) +``` + ## 登陆页面 ![alt text](login.png) +1. UI + +```vue + +``` + +2. 对接 + +```js +// 表单的提交 +const handleSubmit = async (data) => { + // 判断表单是否验证成功 + if (data.errors == null) { + // 通过HttpClient把数据提交给后端 + const resp = await mcenter.Login(data.values) + console.log(resp) + } +} +``` + +3. 状态处理(useStorage) + +```sh +npm i @vueuse/core +``` + +```sh +import { useStorage } from '@vueuse/core' + +export default useStorage('token', {}, localStorage, { mergeDefaults: true }) +``` + +```js +// 表单的提交 +const handleSubmit = async (data) => { + // 判断表单是否验证成功 + if (data.errors == null) { + // 通过HttpClient把数据提交给后端 + const resp = await mcenter.Login(data.values) + // 用户登录后,这些用户信息我们怎么保存喃 1. cookie, session storage, localstorage + // localStorage.setItem('token', JSON.stringify(resp)) + // localStorage.getItem('token') + // 把 localStorage 做成响应式的 + // https://cn.vuejs.org/guide/reusability/composables.html + token.value = resp + } +} +``` + +4. 登录成功后进行跳转 + +```js +// 登录完成后,需要跳转到后台页面 +// location.assign('/users/eduardo') +// vue router对象, 提供路由跳转的功能 +// 字符串路径 +// router.push('/users/eduardo') +// 指定到组件名称 +router.push({ name: 'HomePage' }) +``` + ## Layout(多套子系统) ## 具体子页面 diff --git a/devcloud/web/package-lock.json b/devcloud/web/package-lock.json index 5acad3f..021aa31 100644 --- a/devcloud/web/package-lock.json +++ b/devcloud/web/package-lock.json @@ -8,6 +8,8 @@ "name": "web", "version": "0.0.0", "dependencies": { + "@vueuse/core": "^13.6.0", + "axios": "^1.11.0", "vue": "^3.5.18", "vue-router": "^4.5.1" }, @@ -1598,6 +1600,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-vue": { "version": "6.0.1", "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", @@ -1852,6 +1860,44 @@ "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==", "license": "MIT" }, + "node_modules/@vueuse/core": { + "version": "13.6.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-13.6.0.tgz", + "integrity": "sha512-DJbD5fV86muVmBgS9QQPddVX7d9hWYswzlf4bIyUD2dj8GC46R1uNClZhVAmsdVts4xb2jwp1PbpuiA50Qee1A==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "13.6.0", + "@vueuse/shared": "13.6.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "13.6.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-13.6.0.tgz", + "integrity": "sha512-rnIH7JvU7NjrpexTsl2Iwv0V0yAx9cw7+clymjKuLSXG0QMcLD0LDgdNmXic+qL0SGvgSVPEpM9IDO/wqo1vkQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "13.6.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-13.6.0.tgz", + "integrity": "sha512-pDykCSoS2T3fsQrYqf9SyF0QXWHmcGPQ+qiOVjlYSzlWd9dgppB2bFSM1GgKKkt7uzn0BBMV3IbJsUfHG2+BCg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz", @@ -1925,6 +1971,23 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.11.0", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/b-tween": { "version": "0.3.3", "resolved": "https://registry.npmmirror.com/b-tween/-/b-tween-0.3.3.tgz", @@ -2023,6 +2086,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", @@ -2130,6 +2206,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compute-scroll-into-view": { "version": "1.0.20", "resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", @@ -2276,6 +2364,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.194", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", @@ -2305,6 +2416,51 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.8", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.8.tgz", @@ -2743,6 +2899,42 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", @@ -2758,6 +2950,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2768,6 +2969,43 @@ "node": ">=6.9.0" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "9.0.1", "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-9.0.1.tgz", @@ -2811,6 +3049,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", @@ -2821,6 +3071,45 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", @@ -3155,6 +3444,36 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", @@ -3526,6 +3845,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", diff --git a/devcloud/web/package.json b/devcloud/web/package.json index ccd99cd..6158d8a 100644 --- a/devcloud/web/package.json +++ b/devcloud/web/package.json @@ -14,6 +14,8 @@ "format": "prettier --write src/" }, "dependencies": { + "@vueuse/core": "^13.6.0", + "axios": "^1.11.0", "vue": "^3.5.18", "vue-router": "^4.5.1" }, diff --git a/devcloud/web/src/api/README.md b/devcloud/web/src/api/README.md new file mode 100644 index 0000000..8293660 --- /dev/null +++ b/devcloud/web/src/api/README.md @@ -0,0 +1 @@ +# 存放所有后端的API调用封装 diff --git a/devcloud/web/src/api/client.js b/devcloud/web/src/api/client.js new file mode 100644 index 0000000..af2fe5d --- /dev/null +++ b/devcloud/web/src/api/client.js @@ -0,0 +1,31 @@ +import axios from 'axios' +import { Message } from '@arco-design/web-vue' + +// 封装一个axios的实例,http cient实例 +// https://axios-http.com/zh/docs/instance +const client = axios.create({ + timeout: 3000, +}) + +// 拦截API的返回结果, 如果是异常 提取异常信息,并展示 +// 如果正常 则直接返回 API的响应结果 +// https://axios-http.com/zh/docs/interceptors +client.interceptors.response.use( + (data) => { + return data.data + }, + (error) => { + // 提取错误 + var msg = error.message + + // 如果有更加详细的信息 + if (error.response.data.message) { + msg = error.response.data.message + } + + Message.error(msg) + return error + }, +) + +export default client diff --git a/devcloud/web/src/api/mcenter.js b/devcloud/web/src/api/mcenter.js new file mode 100644 index 0000000..b97ee2a --- /dev/null +++ b/devcloud/web/src/api/mcenter.js @@ -0,0 +1,9 @@ +import client from './client' + +var API = { + Login: (data) => { + return client.post('/api/devcloud/v1/token', data) + }, +} + +export default API diff --git a/devcloud/web/src/pages/LoginPage.vue b/devcloud/web/src/pages/LoginPage.vue index 0030004..1a68787 100644 --- a/devcloud/web/src/pages/LoginPage.vue +++ b/devcloud/web/src/pages/LoginPage.vue @@ -6,16 +6,21 @@

欢迎登录

- - + + - - + + @@ -34,18 +39,45 @@ diff --git a/devcloud/web/src/router/index.js b/devcloud/web/src/router/index.js index eb728be..8fa7843 100644 --- a/devcloud/web/src/router/index.js +++ b/devcloud/web/src/router/index.js @@ -7,12 +7,12 @@ const router = createRouter({ routes: [ { path: '/', - name: 'home', + name: 'HomePage', component: HomePage, }, { path: '/login', - name: 'login', + name: 'LoginPage', // route level code-splitting // this generates a separate chunk (About.[hash].js) for this route // which is lazy-loaded when the route is visited. diff --git a/devcloud/web/src/storage/app.js b/devcloud/web/src/storage/app.js new file mode 100644 index 0000000..e69de29 diff --git a/devcloud/web/src/storage/token.js b/devcloud/web/src/storage/token.js new file mode 100644 index 0000000..5c54647 --- /dev/null +++ b/devcloud/web/src/storage/token.js @@ -0,0 +1,3 @@ +import { useStorage } from '@vueuse/core' + +export default useStorage('token', {}, localStorage, { mergeDefaults: true }) diff --git a/devcloud/web/vite.config.js b/devcloud/web/vite.config.js index 4217010..4641b76 100644 --- a/devcloud/web/vite.config.js +++ b/devcloud/web/vite.config.js @@ -6,13 +6,15 @@ import vueDevTools from 'vite-plugin-vue-devtools' // https://vite.dev/config/ export default defineConfig({ - plugins: [ - vue(), - vueDevTools(), - ], + plugins: [vue(), vueDevTools()], resolve: { alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)) + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + server: { + proxy: { + '/api': 'http://127.0.0.1:8080', }, }, })