From cf010e570d587956bc338f04ce7b52026c8e6fa9 Mon Sep 17 00:00:00 2001 From: X1627315083 <1627315083@qq.com> Date: Tue, 3 Feb 2026 11:24:47 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=B5=8B=E8=AF=95version?= =?UTF-8?q?Tree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 200 ++++++++++++++++++ package.json | 1 + src/App.vue | 1 + src/assets/icons/close.svg | 3 + src/router/index.ts | 5 + src/views/home/VersionTree.vue | 35 +++ src/views/home/versionTree/index.vue | 110 ++++++++++ src/views/home/versionTree/tree/index.vue | 71 +++++++ src/views/home/versionTree/tree/view1Item.vue | 70 ++++++ .../home/versionTree/tree/view2/index.vue | 63 ++++++ .../versionTree/tree/view2/speciaiEdge.vue | 45 ++++ .../versionTree/tree/view2/speciaiNode.vue | 55 +++++ 12 files changed, 659 insertions(+) create mode 100644 src/assets/icons/close.svg create mode 100644 src/views/home/VersionTree.vue create mode 100644 src/views/home/versionTree/index.vue create mode 100644 src/views/home/versionTree/tree/index.vue create mode 100644 src/views/home/versionTree/tree/view1Item.vue create mode 100644 src/views/home/versionTree/tree/view2/index.vue create mode 100644 src/views/home/versionTree/tree/view2/speciaiEdge.vue create mode 100644 src/views/home/versionTree/tree/view2/speciaiNode.vue diff --git a/package-lock.json b/package-lock.json index 09371fe..9730553 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "hasInstallScript": true, "dependencies": { + "@vue-flow/core": "^1.48.2", "axios": "^1.3.6", "crypto-js": "^4.2.0", "element-plus": "^2.13.2", @@ -1023,6 +1024,22 @@ "typescript": "*" } }, + "node_modules/@vue-flow/core": { + "version": "1.48.2", + "resolved": "https://registry.npmmirror.com/@vue-flow/core/-/core-1.48.2.tgz", + "integrity": "sha512-raxhgKWE+G/mcEvXJjGFUDYW9rAI3GOtiHR3ZkNpwBWuIaCC1EYiBmKGwJOoNzVFgwO7COgErnK7i08i287AFA==", + "license": "MIT", + "dependencies": { + "@vueuse/core": "^10.5.0", + "d3-drag": "^3.0.0", + "d3-interpolate": "^3.0.1", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + }, + "peerDependencies": { + "vue": "^3.3.0" + } + }, "node_modules/@vue-macros/common": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.1.tgz", @@ -2233,6 +2250,111 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -9203,6 +9325,18 @@ "@volar/vue-language-core": "1.4.4" } }, + "@vue-flow/core": { + "version": "1.48.2", + "resolved": "https://registry.npmmirror.com/@vue-flow/core/-/core-1.48.2.tgz", + "integrity": "sha512-raxhgKWE+G/mcEvXJjGFUDYW9rAI3GOtiHR3ZkNpwBWuIaCC1EYiBmKGwJOoNzVFgwO7COgErnK7i08i287AFA==", + "requires": { + "@vueuse/core": "^10.5.0", + "d3-drag": "^3.0.0", + "d3-interpolate": "^3.0.1", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + } + }, "@vue-macros/common": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.1.tgz", @@ -10078,6 +10212,72 @@ "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, "data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz", diff --git a/package.json b/package.json index c547526..95d0080 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "postinstall": "husky install" }, "dependencies": { + "@vue-flow/core": "^1.48.2", "axios": "^1.3.6", "crypto-js": "^4.2.0", "element-plus": "^2.13.2", diff --git a/src/App.vue b/src/App.vue index 3c78e9f..0c97814 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,6 +13,7 @@ \ No newline at end of file diff --git a/src/views/home/versionTree/index.vue b/src/views/home/versionTree/index.vue new file mode 100644 index 0000000..49c1059 --- /dev/null +++ b/src/views/home/versionTree/index.vue @@ -0,0 +1,110 @@ + + + \ No newline at end of file diff --git a/src/views/home/versionTree/tree/index.vue b/src/views/home/versionTree/tree/index.vue new file mode 100644 index 0000000..22ac5df --- /dev/null +++ b/src/views/home/versionTree/tree/index.vue @@ -0,0 +1,71 @@ + + + \ No newline at end of file diff --git a/src/views/home/versionTree/tree/view1Item.vue b/src/views/home/versionTree/tree/view1Item.vue new file mode 100644 index 0000000..d370ce2 --- /dev/null +++ b/src/views/home/versionTree/tree/view1Item.vue @@ -0,0 +1,70 @@ + + + \ No newline at end of file diff --git a/src/views/home/versionTree/tree/view2/index.vue b/src/views/home/versionTree/tree/view2/index.vue new file mode 100644 index 0000000..014331a --- /dev/null +++ b/src/views/home/versionTree/tree/view2/index.vue @@ -0,0 +1,63 @@ + + + + \ No newline at end of file diff --git a/src/views/home/versionTree/tree/view2/speciaiEdge.vue b/src/views/home/versionTree/tree/view2/speciaiEdge.vue new file mode 100644 index 0000000..ecdb68c --- /dev/null +++ b/src/views/home/versionTree/tree/view2/speciaiEdge.vue @@ -0,0 +1,45 @@ + + + + + + + diff --git a/src/views/home/versionTree/tree/view2/speciaiNode.vue b/src/views/home/versionTree/tree/view2/speciaiNode.vue new file mode 100644 index 0000000..cafd797 --- /dev/null +++ b/src/views/home/versionTree/tree/view2/speciaiNode.vue @@ -0,0 +1,55 @@ + + + + + From 3d7cb5d5d437a773e4e49e8186c755446d4eaaea Mon Sep 17 00:00:00 2001 From: zhangyahui Date: Tue, 3 Feb 2026 13:15:39 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96CSS=20&?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 21 +++---- package-lock.json | 12 ++++ package.json | 1 + src/assets/css/style.css | 37 ++++++++++++- src/assets/css/style.less | 35 +++++++----- src/assets/icons/attach.svg | 3 + src/main.ts | 1 + src/router/index.ts | 77 ++++++++++++++------------ src/views/home/components/Input.vue | 86 +++++++++++++++++++++++++++++ src/views/home/mainInput.vue | 32 +++++++++++ 10 files changed, 240 insertions(+), 65 deletions(-) create mode 100644 src/assets/icons/attach.svg create mode 100644 src/views/home/components/Input.vue create mode 100644 src/views/home/mainInput.vue diff --git a/index.html b/index.html index 148096a..6f42dca 100644 --- a/index.html +++ b/index.html @@ -1,24 +1,19 @@ + - - - - Lane Crawford - - - - - - - - + + + + FiDA +
- + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e30a2f1..5691968 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "element-plus": "^2.13.2", "gsap": "^3.13.0", "markdown-it": "^14.1.0", + "normalize.css": "^8.0.1", "pinia": "^2.0.32", "pinia-persistedstate-plugin": "^0.1.0", "pinia-plugin-persistedstate": "^3.1.0", @@ -5329,6 +5330,12 @@ "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", "license": "BSD-3-Clause" }, + "node_modules/normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==", + "license": "MIT" + }, "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmmirror.com/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -12459,6 +12466,11 @@ "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" }, + "normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" + }, "npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmmirror.com/npm-run-all/-/npm-run-all-4.1.5.tgz", diff --git a/package.json b/package.json index 0ef6651..703d2b4 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "element-plus": "^2.13.2", "gsap": "^3.13.0", "markdown-it": "^14.1.0", + "normalize.css": "^8.0.1", "pinia": "^2.0.32", "pinia-persistedstate-plugin": "^0.1.0", "pinia-plugin-persistedstate": "^3.1.0", diff --git a/src/assets/css/style.css b/src/assets/css/style.css index 417e454..a1102e0 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -1,6 +1,14 @@ -* { - padding: 0; +body, +html, +div, +ul, +li, +h1, +h2, +h3, +p { margin: 0; + padding: 0; } html, body, @@ -17,3 +25,28 @@ body, transform: rotate(360deg); } } +.flex { + display: flex; +} +.flex-col { + flex-direction: column; +} +.flex-1 { + flex: 1; +} +.flex-center { + align-items: center; + justify-content: center; +} +.flex-between { + justify-content: space-between; +} +.align-center { + align-items: center; +} +.relative { + position: relative; +} +.absolute { + position: absolute; +} diff --git a/src/assets/css/style.less b/src/assets/css/style.less index 36890a8..d146a31 100644 --- a/src/assets/css/style.less +++ b/src/assets/css/style.less @@ -1,23 +1,30 @@ -* { - padding: 0; - margin: 0; +body, +html, +div, +ul, +li, +h1, +h2, +h3, +p { + margin: 0; + padding: 0; } html, body, #app { - width: 100%; - height: 100%; - overflow: hidden; + width: 100%; + height: 100%; + overflow: hidden; } - @keyframes loading { - 0% { - transform: rotate(0deg); - } + 0% { + transform: rotate(0deg); + } - 100% { - transform: rotate(360deg); - } -} \ No newline at end of file + 100% { + transform: rotate(360deg); + } +} diff --git a/src/assets/icons/attach.svg b/src/assets/icons/attach.svg new file mode 100644 index 0000000..26caec9 --- /dev/null +++ b/src/assets/icons/attach.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/main.ts b/src/main.ts index a6da966..171751e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,6 +14,7 @@ import flexible from "./utils/flexible.js"; import "./router/router-config" // 路由守卫,做动态路由的地方 import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' +import 'normalize.css' const app = createApp(App) app.use(router) diff --git a/src/router/index.ts b/src/router/index.ts index 80a40d3..1886d42 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -7,42 +7,47 @@ import { createRouter, createWebHistory } from 'vue-router' * 3. 路由的name默认是文件名,如果文件名与name不一致,通过defineOptions({ name: 'componentName' })来设置 */ const router = createRouter({ - history: createWebHistory('/'), - // history: createWebHistory(import.meta.env.VITE_APP_URL), - routes: [ - { - path: '/', - redirect: '/home' - }, - { - path: '/', - name: 'index', - component: () => import('../views/login/index.vue'), - }, - { - path: '/login', - name: 'login', - component: () => import('../views/login/login.vue'), - }, - { - path: '/home', - name: 'home', - component: () => import('../views/home/index.vue'), - children: [ - { - path: 'test', - name: 'test', - component: () => import('../views/home/test.vue'), - meta: { topNavStyle: '2' } - } - ] - }, - { - path: '/:pathMatch(.*)', - name: '404', - component: () => import('../views/404.vue'), - } - ] + history: createWebHistory('/'), + // history: createWebHistory(import.meta.env.VITE_APP_URL), + routes: [ + { + path: '/', + redirect: '/home' + }, + { + path: '/', + name: 'index', + component: () => import('../views/login/index.vue') + }, + { + path: '/login', + name: 'login', + component: () => import('../views/login/login.vue') + }, + { + path: '/home', + name: 'home', + component: () => import('../views/home/index.vue'), + children: [ + { + path: 'test', + name: 'test', + component: () => import('../views/home/test.vue'), + meta: { topNavStyle: '2' } + }, + { + path: 'mainInput', + name: 'mainInput', + component: () => import('../views/home/mainInput.vue') + } + ] + }, + { + path: '/:pathMatch(.*)', + name: '404', + component: () => import('../views/404.vue') + } + ] }) export default router diff --git a/src/views/home/components/Input.vue b/src/views/home/components/Input.vue new file mode 100644 index 0000000..dfb2fa8 --- /dev/null +++ b/src/views/home/components/Input.vue @@ -0,0 +1,86 @@ +