diff --git a/package-lock.json b/package-lock.json index fea93f4..eebeba2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.0.0", "dependencies": { "@element-plus/icons-vue": "^2.3.1", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", "axios": "^1.6.2", "dayjs": "^1.11.13", "echarts": "^5.4.3", @@ -58,6 +60,15 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", + "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", @@ -1112,6 +1123,12 @@ "win32" ] }, + "node_modules/@transloadit/prettier-bytes": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz", + "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1119,6 +1136,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@types/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==", + "license": "MIT" + }, "node_modules/@types/lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", @@ -1140,6 +1163,61 @@ "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==", "license": "MIT" }, + "node_modules/@uppy/companion-client": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz", + "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==", + "license": "MIT", + "dependencies": { + "@uppy/utils": "^4.1.2", + "namespace-emitter": "^2.0.1" + } + }, + "node_modules/@uppy/core": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz", + "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==", + "license": "MIT", + "dependencies": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/store-default": "^2.1.1", + "@uppy/utils": "^4.1.3", + "lodash.throttle": "^4.1.1", + "mime-match": "^1.0.2", + "namespace-emitter": "^2.0.1", + "nanoid": "^3.1.25", + "preact": "^10.5.13" + } + }, + "node_modules/@uppy/store-default": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz", + "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==", + "license": "MIT" + }, + "node_modules/@uppy/utils": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz", + "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==", + "license": "MIT", + "dependencies": { + "lodash.throttle": "^4.1.1" + } + }, + "node_modules/@uppy/xhr-upload": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz", + "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==", + "license": "MIT", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.2", + "nanoid": "^3.1.25" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, "node_modules/@vitejs/plugin-vue": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz", @@ -1296,6 +1374,165 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/@wangeditor/basic-modules": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz", + "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==", + "license": "MIT", + "dependencies": { + "is-url": "^1.2.4" + }, + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.throttle": "^4.1.1", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/code-highlight": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz", + "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.23.0" + }, + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/core": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz", + "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==", + "license": "MIT", + "dependencies": { + "@types/event-emitter": "^0.3.3", + "event-emitter": "^0.3.5", + "html-void-elements": "^2.0.0", + "i18next": "^20.4.0", + "scroll-into-view-if-needed": "^2.2.28", + "slate-history": "^0.66.0" + }, + "peerDependencies": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/editor": { + "version": "5.1.23", + "resolved": "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.23.tgz", + "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==", + "license": "MIT", + "dependencies": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "^1.1.7", + "@wangeditor/code-highlight": "^1.0.3", + "@wangeditor/core": "^1.1.19", + "@wangeditor/list-module": "^1.0.5", + "@wangeditor/table-module": "^1.1.4", + "@wangeditor/upload-image-module": "^1.0.2", + "@wangeditor/video-module": "^1.1.4", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/editor-for-vue": { + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz", + "integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==", + "license": "MIT", + "peerDependencies": { + "@wangeditor/editor": ">=5.1.0", + "vue": "^3.0.5" + } + }, + "node_modules/@wangeditor/list-module": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.5.tgz", + "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==", + "license": "MIT", + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/table-module": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.4.tgz", + "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==", + "license": "MIT", + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/upload-image-module": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz", + "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==", + "license": "MIT", + "peerDependencies": { + "@uppy/core": "^2.0.3", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "1.x", + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.foreach": "^4.5.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/video-module": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.4.tgz", + "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==", + "license": "MIT", + "peerDependencies": { + "@uppy/core": "^2.1.4", + "@uppy/xhr-upload": "^2.0.7", + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, "node_modules/async-validator": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", @@ -1374,12 +1611,31 @@ "node": ">= 0.8" } }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/dayjs": { "version": "1.11.13", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", @@ -1409,6 +1665,15 @@ "node": ">=0.10" } }, + "node_modules/dom7": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", + "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "license": "MIT", + "dependencies": { + "ssr-window": "^3.0.0-alpha.1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1516,6 +1781,46 @@ "node": ">= 0.4" } }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -1561,12 +1866,46 @@ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1729,6 +2068,35 @@ "node": ">= 0.4" } }, + "node_modules/html-void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", + "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/i18next": { + "version": "20.6.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.6.1.tgz", + "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.0" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/immutable": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", @@ -1761,6 +2129,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-hotkey": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", + "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==", + "license": "MIT" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1772,6 +2146,21 @@ "node": ">=0.12.0" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1795,6 +2184,49 @@ "lodash-es": "*" } }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==", + "license": "MIT" + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -1843,6 +2275,15 @@ "node": ">= 0.6" } }, + "node_modules/mime-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", + "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==", + "license": "ISC", + "dependencies": { + "wildcard": "^1.1.0" + } + }, "node_modules/mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", @@ -1855,6 +2296,12 @@ "node": ">= 0.6" } }, + "node_modules/namespace-emitter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==", + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1873,6 +2320,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "license": "ISC" + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -1963,6 +2416,25 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/preact": { + "version": "10.27.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.1.tgz", + "integrity": "sha512-V79raXEWch/rbqoNc7nT9E4ep7lu+mI3+sBmfRD4i1M73R3WLYcCtdI0ibxGVf4eQL8ZIz2nFacqEC+rmnOORQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -2050,6 +2522,47 @@ "@parcel/watcher": "^2.4.1" } }, + "node_modules/scroll-into-view-if-needed": { + "version": "2.2.31", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz", + "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^1.0.20" + } + }, + "node_modules/slate": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz", + "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==", + "license": "MIT", + "dependencies": { + "immer": "^9.0.6", + "is-plain-object": "^5.0.0", + "tiny-warning": "^1.0.3" + } + }, + "node_modules/slate-history": { + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz", + "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^5.0.0" + }, + "peerDependencies": { + "slate": ">=0.65.3" + } + }, + "node_modules/snabbdom": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.2.tgz", + "integrity": "sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==", + "license": "MIT", + "engines": { + "node": ">=12.17.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2059,6 +2572,18 @@ "node": ">=0.10.0" } }, + "node_modules/ssr-window": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", + "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2079,6 +2604,12 @@ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", "license": "0BSD" }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "license": "ISC" + }, "node_modules/vite": { "version": "5.4.19", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", @@ -2252,6 +2783,12 @@ "vue": "^3.2.0" } }, + "node_modules/wildcard": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", + "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==", + "license": "MIT" + }, "node_modules/zrender": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", diff --git a/package.json b/package.json index f732a75..16ebc3d 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.3.1", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", "axios": "^1.6.2", "dayjs": "^1.11.13", "echarts": "^5.4.3", diff --git a/src/components/HorizontalImageDisplay.vue b/src/components/HorizontalImageDisplay.vue new file mode 100644 index 0000000..16f774a --- /dev/null +++ b/src/components/HorizontalImageDisplay.vue @@ -0,0 +1,349 @@ + + + + + \ No newline at end of file diff --git a/src/components/ImageUpload.vue b/src/components/ImageUpload.vue index 1b08de6..e7b6a78 100644 --- a/src/components/ImageUpload.vue +++ b/src/components/ImageUpload.vue @@ -202,10 +202,10 @@ defineExpose({ } .upload-area { - width: 200px; - height: 120px; - border: 2px dashed #d9d9d9; - border-radius: 6px; + width: 240px; + height: 160px; + border: 2px dashed #e4e7ed; + border-radius: 12px; cursor: pointer; position: relative; overflow: hidden; @@ -213,18 +213,22 @@ defineExpose({ display: flex; align-items: center; justify-content: center; - background-color: #fafafa; + background: linear-gradient(135deg, #fafbfc 0%, #f5f7fa 100%); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); } .upload-area:hover { border-color: #409eff; - background-color: #f0f9ff; + background: linear-gradient(135deg, #f0f9ff 0%, #e6f4ff 100%); + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(64, 158, 255, 0.15); } .upload-area.uploading { border-color: #409eff; - background-color: #f0f9ff; + background: linear-gradient(135deg, #f0f9ff 0%, #e6f4ff 100%); cursor: not-allowed; + box-shadow: 0 4px 16px rgba(64, 158, 255, 0.2); } .upload-area.has-image { @@ -238,19 +242,23 @@ defineExpose({ } .upload-icon { - font-size: 28px; - color: #8c939d; - margin-bottom: 8px; + font-size: 36px; + color: #409eff; + margin-bottom: 12px; + transition: all 0.3s ease; } .upload-text { - font-size: 14px; - margin-bottom: 4px; + font-size: 15px; + font-weight: 500; + color: #303133; + margin-bottom: 6px; } .upload-hint { font-size: 12px; - color: #c0c4cc; + color: #909399; + line-height: 1.4; } .upload-progress { @@ -283,6 +291,7 @@ defineExpose({ height: 100%; object-fit: cover; display: block; + border-radius: 12px; } .image-overlay { @@ -291,13 +300,14 @@ defineExpose({ left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.6); display: flex; align-items: center; justify-content: center; - gap: 8px; + gap: 12px; opacity: 0; - transition: opacity 0.3s ease; + transition: all 0.3s ease; + border-radius: 12px; } .image-preview:hover .image-overlay { @@ -326,20 +336,20 @@ defineExpose({ /* 响应式设计 */ @media (max-width: 768px) { .upload-area { - width: 150px; - height: 100px; + width: 180px; + height: 120px; } .upload-icon { - font-size: 24px; + font-size: 28px; } .upload-text { - font-size: 12px; + font-size: 13px; } .upload-hint { - font-size: 10px; + font-size: 11px; } } \ No newline at end of file diff --git a/src/components/MediaUpload.vue b/src/components/MediaUpload.vue new file mode 100644 index 0000000..961b171 --- /dev/null +++ b/src/components/MediaUpload.vue @@ -0,0 +1,295 @@ + + + + + \ No newline at end of file diff --git a/src/components/RichTextEditor.vue b/src/components/RichTextEditor.vue new file mode 100644 index 0000000..40d4f26 --- /dev/null +++ b/src/components/RichTextEditor.vue @@ -0,0 +1,250 @@ + + + + + \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 401e808..4984ad9 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -90,6 +90,16 @@ const routes = [ requiresAdmin: true } }, + { + path: 'products/:id/specifications', + name: 'ProductSpecifications', + component: () => import('@/views/ProductSpecifications.vue'), + meta: { + title: '商品规格管理 - 积分商城管理系统', + icon: 'Setting', + requiresAdmin: true + } + }, { path: 'orders', name: 'Orders', diff --git a/src/utils/api.js b/src/utils/api.js index f066785..025fa07 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -289,6 +289,26 @@ const api = { cancelAllocation: (allocationId) => request.post(`/admin/matching/cancel-allocation/${allocationId}`) }, + // 商品管理 + products: { + getProducts: (params) => request.get('/products', { params }), + getProductById: (id) => request.get(`/products/${id}`), + createProduct: (data) => request.post('/products', data), + updateProduct: (id, data) => request.put(`/products/${id}`, data), + deleteProduct: (id) => request.delete(`/products/${id}`), + getCategories: () => request.get('/products/categories'), + // 商品规格 + getSpecifications: (productId) => request.get(`/products/${productId}/specifications`), + createSpecification: (productId, data) => request.post(`/products/${productId}/specifications`, data), + updateSpecification: (productId, specId, data) => request.put(`/products/${productId}/specifications/${specId}`, data), + deleteSpecification: (productId, specId) => request.delete(`/products/${productId}/specifications/${specId}`), + // 商品属性 + getAttributes: (productId) => request.get(`/products/${productId}/attributes`), + createAttribute: (productId, data) => request.post(`/products/${productId}/attributes`, data), + updateAttribute: (productId, attrId, data) => request.put(`/products/${productId}/attributes/${attrId}`, data), + deleteAttribute: (productId, attrId) => request.delete(`/products/${productId}/attributes/${attrId}`) + }, + // 为了向后兼容,添加直接的 get、post 等方法 get: (url, config) => request.get(url, config), post: (url, data, config) => request.post(url, data, config), diff --git a/src/views/ProductAttributes.vue b/src/views/ProductAttributes.vue new file mode 100644 index 0000000..82d96d5 --- /dev/null +++ b/src/views/ProductAttributes.vue @@ -0,0 +1,438 @@ + + + + + \ No newline at end of file diff --git a/src/views/ProductForm.vue b/src/views/ProductForm.vue index 004aa4a..720b742 100644 --- a/src/views/ProductForm.vue +++ b/src/views/ProductForm.vue @@ -1,116 +1,347 @@ @@ -118,9 +349,25 @@ import { ref, reactive, onMounted, computed } from 'vue' import { useRoute, useRouter } from 'vue-router' import { ElMessage } from 'element-plus' -import { ArrowLeft } from '@element-plus/icons-vue' +import { + Box, + ArrowLeft, + InfoFilled, + Money, + Picture, + Document, + Setting, + Shop, + Coin, + CreditCard, + Check, + Refresh +} from '@element-plus/icons-vue' import api from '@/utils/api' import ImageUpload from '@/components/ImageUpload.vue' +import MediaUpload from '@/components/MediaUpload.vue' +import HorizontalImageDisplay from '@/components/HorizontalImageDisplay.vue' +import RichTextEditor from '@/components/RichTextEditor.vue' const route = useRoute() const router = useRouter() @@ -130,13 +377,32 @@ const categories = ref(['数码产品', '生活用品', '食品饮料', '图书 const isEdit = computed(() => !!route.params.id) +// 商品状态开关 +const statusActive = computed({ + get: () => form.status, + set: (value) => { + form.status = value + } +}) + +// 处理状态变化 +const handleStatusChange = (value) => { + form.status = value +} + const form = reactive({ name: '', category: '', price: null, points: null, + rongdou_price: null, stock: null, image: '', + images: [], + videos: [], + shop_name: '', + shop_avatar: '', + payment_methods: ['points'], description: '', details: '', status: 'active' @@ -158,6 +424,12 @@ const rules = { { required: true, message: '请输入积分价格', trigger: 'blur' }, { type: 'number', min: 1, message: '积分价格必须大于0', trigger: 'blur' } ], + rongdou_price: [ + { type: 'number', min: 0, message: '融豆价格不能小于0', trigger: 'blur' } + ], + payment_methods: [ + { required: true, message: '请选择至少一种支付方式', trigger: 'change' } + ], stock: [ { required: true, message: '请输入库存数量', trigger: 'blur' }, { type: 'number', min: 0, message: '库存数量不能小于0', trigger: 'blur' } @@ -170,8 +442,19 @@ const rules = { { min: 10, max: 500, message: '商品描述长度在 10 到 500 个字符', trigger: 'blur' } ], details: [ - { required: true, message: '请输入商品详情', trigger: 'blur' }, - { min: 20, max: 2000, message: '商品详情长度在 20 到 2000 个字符', trigger: 'blur' } + { required: true, message: '请输入商品详情', trigger: 'change' }, + { + validator: (rule, value, callback) => { + if (!value || value.trim() === '' || value === '


') { + callback(new Error('请输入商品详情')) + } else if (value.length < 20) { + callback(new Error('商品详情内容过少,请详细描述商品信息')) + } else { + callback() + } + }, + trigger: 'change' + } ], status: [ { required: true, message: '请选择商品状态', trigger: 'change' } @@ -183,23 +466,40 @@ const loadProduct = async () => { if (!isEdit.value) return try { - const response = await api.get(`/products/${route.params.id}`) + const response = await api.products.getProductById(route.params.id) const {data} = response.data let product = data.product - console.log(data,'1111'); + + + // 检查 product 是否存在 + if (!product) { + ElMessage.error('商品数据不存在') + router.push('/products') + return + } // 将后端字段映射到前端字段名 + console.log(form,product); + Object.assign(form, { - name: product.name, - category: product.category, - price: product.price, - points: product.points, // 后端 points_price -> 前端 points - stock: product.stock, - image: product.image_url, // 后端 image_url -> 前端 image - description: product.description, - details: product.details, - status: product.status + name: product.name || '', + category: product.category || '', + price: product.price || 0, + points: product.points_price || 0, // 后端 points_price -> 前端 points + rongdou_price: product.rongdou_price || 0, + stock: product.stock || 0, + image: product.image_url || '', // 后端 image_url -> 前端 image + images: product.images || [], + videos: product.videos || [], + shop_name: product.shop_name || '', + shop_avatar: product.shop_avatar || '', + payment_methods: product.payment_methods || [], + description: product.description || '', + details: product.details || '', + status: product.status || 'active' }) + console.log('表单数据:', form); + } catch (error) { ElMessage.error('加载商品信息失败',error) // router.back() @@ -220,18 +520,24 @@ const submitForm = async () => { category: form.category, price: form.price, points_price: form.points, // 前端 points -> 后端 points_price + rongdou_price: form.rongdou_price || 0, stock: form.stock, image_url: form.image, // 前端 image -> 后端 image_url + images: JSON.stringify(form.images), + videos: JSON.stringify(form.videos), + shop_name: form.shop_name, + shop_avatar: form.shop_avatar, + payment_methods: JSON.stringify(form.payment_methods), description: form.description, details: form.details, status: form.status } if (isEdit.value) { - await api.put(`/products/${route.params.id}`, submitData) + await api.products.updateProduct(route.params.id, submitData) ElMessage.success('商品更新成功') } else { - await api.post('/products', submitData) + await api.products.createProduct(submitData) ElMessage.success('商品创建成功') } @@ -258,9 +564,54 @@ const handleImageUploadSuccess = (data) => { console.log('图片上传成功:', data) } -// 图片上传失败处理 +// 店家头像上传成功处理 +const handleShopAvatarUploadSuccess = (data) => { + console.log('店家头像上传成功:', data) +} + +// 商品相册上传成功处理 +const handleImagesUploadSuccess = (data) => { + console.log('商品相册上传成功:', data) + // 不需要手动添加图片,HorizontalImageDisplay组件已经通过v-model自动更新了form.images + ElMessage.success('图片上传成功') +} + +// 商品视频上传成功处理 +const handleVideosUploadSuccess = (data) => { + console.log('商品视频上传成功:', data) + // 不需要手动添加视频,HorizontalImageDisplay组件已经通过v-model自动更新了form.videos + ElMessage.success('视频上传成功') +} + +// 图片/视频上传失败处理 const handleImageUploadError = (error) => { - console.error('图片上传失败:', error) + console.error('上传失败:', error) + + // 根据错误类型显示不同的提示信息 + let errorMessage = '上传失败,请重试' + + if (error && error.message) { + if (error.message.includes('size')) { + errorMessage = '文件大小超出限制' + } else if (error.message.includes('type')) { + errorMessage = '文件格式不支持' + } else if (error.message.includes('network')) { + errorMessage = '网络错误,请检查网络连接' + } else { + errorMessage = error.message + } + } + + ElMessage.error(errorMessage) +} + +// 处理富文本编辑器内容变化 +const handleDetailsChange = (content) => { + form.details = content + // 触发表单验证 + if (formRef.value) { + formRef.value.validateField('details') + } } onMounted(() => { @@ -270,27 +621,485 @@ onMounted(() => { \ No newline at end of file diff --git a/src/views/ProductSpecifications.vue b/src/views/ProductSpecifications.vue new file mode 100644 index 0000000..8772595 --- /dev/null +++ b/src/views/ProductSpecifications.vue @@ -0,0 +1,315 @@ + + + + + \ No newline at end of file diff --git a/src/views/Products.vue b/src/views/Products.vue index b4cdbc5..7dfae5e 100644 --- a/src/views/Products.vue +++ b/src/views/Products.vue @@ -60,6 +60,19 @@ {{ row.points }} 积分 + + + + + + @@ -83,6 +96,13 @@ > 编辑 + + 规格 + { ...filters } - const {data} = await api.get('/products', { params }) + const {data} = await api.products.getProducts(params) products.value = data.data.products pagination.total = data.data.total } catch (error) { @@ -163,7 +183,7 @@ const loadProducts = async () => { // 加载商品分类 const loadCategories = async () => { try { - const {data} = await api.get('/products/categories') + const {data} = await api.products.getCategories() categories.value = data.data.categories } catch (error) { console.error('加载分类失败:', error) @@ -201,7 +221,7 @@ const toggleStatus = async (product) => { ) const newStatus = product.status === 'active' ? 'inactive' : 'active' - await api.put(`/products/${product.id}`, { status: newStatus }) + await api.products.updateProduct(product.id, { status: newStatus }) ElMessage.success(`${action}成功`) loadProducts() @@ -225,7 +245,7 @@ const deleteProduct = async (product) => { } ) - await api.delete(`/products/${product.id}`) + await api.products.deleteProduct(product.id) ElMessage.success('删除成功') loadProducts() } catch (error) { @@ -235,6 +255,11 @@ const deleteProduct = async (product) => { } } +// 查看商品规格 +const viewSpecs = (id) => { + router.push(`/products/${id}/specifications`) +} + // 格式化日期 const formatDate = (dateString) => { return new Date(dateString).toLocaleString('zh-CN') @@ -279,6 +304,22 @@ onMounted(() => { font-weight: 500; } +.rongdou-text { + color: #67c23a; + font-weight: 500; +} + +.shop-info { + display: flex; + align-items: center; + gap: 8px; +} + +.shop-info span { + font-size: 12px; + color: #606266; +} + .pagination { margin-top: 20px; display: flex; diff --git a/vite.config.js b/vite.config.js index 4ffd7ec..125e8ff 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,8 +4,8 @@ import { resolve } from 'path' // https://vitejs.dev/config/ export default defineConfig({ - base: '/admin', - // base: '/', + // base: '/admin', + base: '/', plugins: [vue()], resolve: { alias: { @@ -19,10 +19,10 @@ export default defineConfig({ target: 'http://localhost:3000', changeOrigin: true }, - '/admin': { - target: 'http://localhost:3000', - changeOrigin: true - }, + // '/admin': { + // target: 'http://localhost:3000', + // changeOrigin: true + // }, '/uploads': { target: 'http://localhost:3000', changeOrigin: true