fix: mpv completed; add ci
This commit is contained in:
33
.gitea/workflows/build.yaml
Normal file
33
.gitea/workflows/build.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Docker Image CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gitea-official-runner
|
||||
container:
|
||||
image: harbor.merlin.xin/testing/merlin/builder:v0.0.0
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: docker login
|
||||
env:
|
||||
HARBOR_USERNAME: ${{ secrets.HARBOR_ROBOT }}
|
||||
HARBOR_PASSWORD: ${{ secrets.HARBOR_ROBOT_SECRET }}
|
||||
HARBOR_URL: ${{ vars.HARBOR_URL }}
|
||||
run: docker login ${HARBOR_URL} -u ${HARBOR_USERNAME} -p ${HARBOR_PASSWORD}
|
||||
- name: Build and push Docker images
|
||||
env:
|
||||
HARBOR_URL: ${{ vars.HARBOR_URL }}
|
||||
TAG: ${{ github.sha }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
ROOT_DIR=$(pwd)
|
||||
IMAGE_NAME="${HARBOR_URL}/testing/$REPOSITORY:${TAG}"
|
||||
echo "Building image: ${IMAGE_NAME}"
|
||||
docker build -t ${IMAGE_NAME} .
|
||||
echo "Pushing image: ${IMAGE_NAME}"
|
||||
docker push ${IMAGE_NAME}
|
||||
echo "Successfully pushed: ${IMAGE_NAME}"
|
||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM harbor.merlin.xin/mirrors/docker.io/library/node:20-bullseye AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN --mount=type=cache,target=/root/.npm \
|
||||
npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
|
||||
FROM harbor.merlin.xin/mirrors/docker.io/library/nginx:alpine
|
||||
|
||||
COPY --from=build /app/dist /app/dist
|
||||
173
package-lock.json
generated
173
package-lock.json
generated
@@ -82,9 +82,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@element-plus/icons-vue": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz",
|
||||
"integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz",
|
||||
"integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"vue": "^3.2.0"
|
||||
@@ -924,9 +924,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.16",
|
||||
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.16.tgz",
|
||||
"integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==",
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/lodash-es": {
|
||||
@@ -934,6 +934,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
@@ -1196,18 +1197,19 @@
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.8.4.tgz",
|
||||
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz",
|
||||
"integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -1262,7 +1264,7 @@
|
||||
},
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1299,7 +1301,7 @@
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1352,9 +1354,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz",
|
||||
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
|
||||
"version": "1.11.18",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
|
||||
"integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/deep-pick-omit": {
|
||||
@@ -1371,7 +1373,7 @@
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1404,7 +1406,7 @@
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1417,24 +1419,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/element-plus": {
|
||||
"version": "2.9.7",
|
||||
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.7.tgz",
|
||||
"integrity": "sha512-6vjZh5SXBncLhUwJGTVKS5oDljfgGMh6J4zVTeAZK3YdMUN76FgpvHkwwFXocpJpMbii6rDYU3sgie64FyPerQ==",
|
||||
"version": "2.11.5",
|
||||
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.11.5.tgz",
|
||||
"integrity": "sha512-O+bIVHQCjUDm4GiIznDXRoS8ar2TpWLwfOGnN/Aam0VXf5kbuc4SxdKKJdovWNxmxeqbcwjsSZPKgtXNcqys4A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "^3.4.1",
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@floating-ui/dom": "^1.0.1",
|
||||
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@vueuse/core": "^9.1.0",
|
||||
"async-validator": "^4.2.5",
|
||||
"dayjs": "^1.11.13",
|
||||
"escape-html": "^1.0.3",
|
||||
"dayjs": "^1.11.18",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash-unified": "^1.0.2",
|
||||
"lodash-unified": "^1.0.3",
|
||||
"memoize-one": "^6.0.0",
|
||||
"normalize-wheel-es": "^1.2.0"
|
||||
},
|
||||
@@ -1462,7 +1463,7 @@
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1471,7 +1472,7 @@
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1480,7 +1481,7 @@
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1492,7 +1493,7 @@
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1546,12 +1547,6 @@
|
||||
"@esbuild/win32-x64": "0.25.2"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
||||
@@ -1634,14 +1629,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/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": {
|
||||
@@ -1665,7 +1661,7 @@
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -1674,7 +1670,7 @@
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1698,7 +1694,7 @@
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1772,7 +1768,7 @@
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1784,7 +1780,7 @@
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1796,7 +1792,7 @@
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1811,7 +1807,7 @@
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1935,13 +1931,15 @@
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash-unified": {
|
||||
"version": "1.0.3",
|
||||
@@ -1977,7 +1975,7 @@
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2014,7 +2012,7 @@
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2023,7 +2021,7 @@
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2506,13 +2504,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.12.tgz",
|
||||
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.3",
|
||||
"picomatch": "^4.0.2"
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
@@ -2522,10 +2520,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.4.3",
|
||||
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.3.tgz",
|
||||
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
@@ -2536,10 +2537,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -2736,15 +2738,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.2.6",
|
||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.2.6.tgz",
|
||||
"integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
|
||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.30.1"
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.13"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -2807,11 +2813,44 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.13",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz",
|
||||
"integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.13",
|
||||
"@vue/compiler-sfc": "3.5.13",
|
||||
|
||||
@@ -14,6 +14,8 @@ const userInfo = userInfoStore();
|
||||
const vditorRef = ref(null);
|
||||
let vditor = null;
|
||||
|
||||
const emit = defineEmits(['ready'])
|
||||
|
||||
// 定义 localStorage 的 key
|
||||
const STORAGE_KEY = 'publishArticle';
|
||||
|
||||
@@ -54,6 +56,7 @@ onMounted(() => {
|
||||
}
|
||||
},
|
||||
after() {
|
||||
emit('ready');
|
||||
console.log('Vditor 初始化完成');
|
||||
// 初始化后,加载本地缓存内容
|
||||
const cachedContent = localStorage.getItem(STORAGE_KEY);
|
||||
|
||||
@@ -41,11 +41,6 @@ const router = createRouter({
|
||||
component: () => import("@/views/admin/admin.vue"),
|
||||
|
||||
children: [
|
||||
// {
|
||||
// path: "/",
|
||||
// name: "dashboard",
|
||||
// component: () => import("@/views/admin/dashboard.vue"),
|
||||
// },
|
||||
{
|
||||
path: "posts",
|
||||
name: "posts",
|
||||
@@ -62,14 +57,6 @@ const router = createRouter({
|
||||
title: "新闻管理",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "projects",
|
||||
name: "projects",
|
||||
component: () => import("@/views/admin/projects.vue"),
|
||||
meta: {
|
||||
title: "项目管理",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "details",
|
||||
name: "details",
|
||||
@@ -80,21 +67,6 @@ const router = createRouter({
|
||||
name: "comments",
|
||||
component: () => import("@/views/admin/comments.vue"),
|
||||
},
|
||||
// {
|
||||
// path: "tags",
|
||||
// name: "tags",
|
||||
// component: () => import("@/views/admin/tags.vue"),
|
||||
// },
|
||||
// {
|
||||
// path: "users",
|
||||
// name: "users",
|
||||
// component: () => import("@/views/admin/users.vue"),
|
||||
// },
|
||||
// {
|
||||
// path: "settings",
|
||||
// name: "settings",
|
||||
// component: () => import("@/views/admin/settings.vue"),
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -78,8 +78,9 @@ export const viewDetailsStore = defineStore("viewDetails", {
|
||||
id: "",
|
||||
title: "",
|
||||
content: "",
|
||||
created: "",
|
||||
updated: "",
|
||||
cover: "",
|
||||
published: "",
|
||||
related: "",
|
||||
},
|
||||
}),
|
||||
actions: {
|
||||
@@ -87,8 +88,9 @@ export const viewDetailsStore = defineStore("viewDetails", {
|
||||
this.detail.id = data.id;
|
||||
this.detail.title = data.title;
|
||||
this.detail.content = data.content;
|
||||
this.detail.created = data.created;
|
||||
this.detail.updated = data.updated;
|
||||
this.detail.cover = data.cover;
|
||||
this.detail.published = data.published;
|
||||
this.detail.related = data.related;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -7,22 +7,24 @@ export const userInfoStore = defineStore(
|
||||
const token = ref(null);
|
||||
|
||||
const user = reactive({
|
||||
u_id: "",
|
||||
u_name: "",
|
||||
u_avatar: "@/assets/defaultavatar.jpg",
|
||||
u_account: "",
|
||||
id: "",
|
||||
name: "",
|
||||
profile: "@/assets/defaultavatar.jpg",
|
||||
account: "",
|
||||
role: "",
|
||||
});
|
||||
|
||||
const clearUserInfo = () => {
|
||||
this.token.value = null;
|
||||
this.user = {
|
||||
u_id: "",
|
||||
u_name: "",
|
||||
u_avatar: "@/assets/defaultavatar.jpg",
|
||||
u_account: "",
|
||||
role: "",
|
||||
};
|
||||
token.value = null;
|
||||
|
||||
user.id = "";
|
||||
user.name = "";
|
||||
user.profile = "@/assets/defaultavatar.jpg";
|
||||
user.account = "";
|
||||
user.role = "";
|
||||
|
||||
// 清除本地存储的用户信息
|
||||
localStorage.removeItem("userInfo");
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
.show-top-text{
|
||||
text-align: center;
|
||||
}
|
||||
.newsbox {
|
||||
.newsbox, .articlesbox{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.news {
|
||||
.news, .articles{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
@@ -32,7 +32,7 @@
|
||||
flex: 2;
|
||||
height: 100px;
|
||||
}
|
||||
.newspic {
|
||||
.newspic, .articlespic{
|
||||
display: inline-block;
|
||||
background-color: #5b5a5a;
|
||||
width: 20%;
|
||||
@@ -40,7 +40,7 @@
|
||||
max-width: 130px;
|
||||
height: 100%;
|
||||
}
|
||||
.newscontent {
|
||||
.newscontent, .articlescontent{
|
||||
margin-right: auto;
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
|
||||
@@ -18,12 +18,6 @@
|
||||
</el-icon>
|
||||
<span>文章管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/admin/projects">
|
||||
<el-icon>
|
||||
<document />
|
||||
</el-icon>
|
||||
<span>项目管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/admin/comments">
|
||||
<el-icon><chat-line-round /></el-icon>
|
||||
<span>评论管理</span>
|
||||
|
||||
@@ -3,30 +3,33 @@
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span>文章列表</span>
|
||||
<el-button type="primary" @click="openAddArticleModal = true">新增文章</el-button>
|
||||
<el-button type="primary" @click="openAddarticlesModal = true">新增文章</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="title" label="标题" />
|
||||
<el-table-column prop="created" label="创建时间" />
|
||||
<el-table-column prop="updated" label="更新时间" />
|
||||
<el-table-column prop="published" label="发布时间" />
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="openDetails(scope.row)">查看</el-button>
|
||||
<el-button size="small">编辑</el-button>
|
||||
<el-button size="small" @click="edit(scope)">编辑</el-button>
|
||||
<el-button size="small" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="openAddArticleModal" title="新增文章" style="height: 70%; width: 80%;">
|
||||
<el-input size="large" v-model="title" prefix-icon="el-icon-edit" placeholder="请输入文章标题"></el-input>
|
||||
<MarkdownEditor ref="editor" />
|
||||
<el-button type="primary" @click="submitArticle">发布</el-button>
|
||||
<el-dialog v-model="openAddarticlesModal" title="新增文章" style="height: 70%; width: 80%;">
|
||||
<el-input size="large" v-model=title prefix-icon="el-icon-edit" placeholder="请输入文章标题"></el-input>
|
||||
<MarkdownEditor ref="editor1" @ready="editor1ready" />
|
||||
<el-button type="primary" @click="submit()">发布</el-button>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="openEditarticlesModal" title="编辑文章" style="height: 70%; width: 80%;">
|
||||
<el-input size="large" v-model=title prefix-icon="el-icon-edit" placeholder="请输入文章标题"></el-input>
|
||||
<MarkdownEditor ref="editor2" @ready="editor2ready" />
|
||||
<el-button type="primary" @click="update()">更新</el-button>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -35,35 +38,45 @@ import { ElMessage } from 'element-plus'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import axios from 'axios'
|
||||
import MarkdownEditor from '@/components/MarkdownEditor.vue'
|
||||
import { articleStore, detailsStore } from '@/store/details'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Edit } from '@element-plus/icons-vue'
|
||||
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const detail = detailsStore()
|
||||
const articleinfo = articleStore()
|
||||
const userinfo = userInfoStore()
|
||||
|
||||
const openAddArticleModal = ref(false)
|
||||
const openEditarticlesModal =ref(false)
|
||||
const openAddarticlesModal = ref(false)
|
||||
|
||||
const editor = ref(null)
|
||||
const id = ref('')
|
||||
const title = ref('')
|
||||
const content = ref('')
|
||||
|
||||
const page = ref(1)
|
||||
const pageSize = ref(5)
|
||||
const total = ref()
|
||||
|
||||
const title = ref("")
|
||||
const tableData = ref([
|
||||
])
|
||||
const editor1 = ref(null)
|
||||
const editor2 = ref(null)
|
||||
|
||||
const getArticle = async () => {
|
||||
const tableData = ref([])
|
||||
|
||||
const edit = (scope) => {
|
||||
openEditarticlesModal.value = true
|
||||
id.value = scope.row.id
|
||||
title.value = scope.row.title
|
||||
content.value = scope.row.content
|
||||
}
|
||||
|
||||
|
||||
const editor1ready = () =>{
|
||||
title.value = ''
|
||||
editor1.value.setContent('')
|
||||
}
|
||||
|
||||
const editor2ready = () =>{
|
||||
editor2.value.setContent(content.value)
|
||||
}
|
||||
|
||||
const getarticles = async () => {
|
||||
try {
|
||||
const response = await axios.get("/api/admin/get/article", {
|
||||
headers: {
|
||||
Authorization: "Bearer " + userinfo.token,
|
||||
},
|
||||
const response = await axios.get("/api/blog/get/articles", {
|
||||
params: {
|
||||
current: page.value,
|
||||
size: pageSize.value
|
||||
@@ -75,55 +88,68 @@ const getArticle = async () => {
|
||||
}
|
||||
tableData.value = response.data.data.records
|
||||
total.value = response.data.data.total
|
||||
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ElMessage.error("获取文章失败")
|
||||
}
|
||||
}
|
||||
|
||||
const submitArticle = async () => {
|
||||
const markdownContent = editor.value.getContent()
|
||||
console.log("提交的内容:", markdownContent)
|
||||
try {
|
||||
const response = await axios.post("/api/admin/publish/article", {
|
||||
|
||||
|
||||
const submit = async () => {
|
||||
try{
|
||||
const response = await axios.post("/api/admin/add/article", {
|
||||
title: title.value,
|
||||
content: markdownContent,
|
||||
content: editor1.value.getContent(),
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: "Bearer " + userinfo.token,
|
||||
contentType: "application/json"
|
||||
},
|
||||
}
|
||||
})
|
||||
if (!response.data.code === 200) {
|
||||
if (response.data.code !== 200) {
|
||||
ElMessage.error(response.data.message)
|
||||
return
|
||||
}
|
||||
ElMessage.success("发布成功")
|
||||
openAddArticleModal.value = false
|
||||
getArticle()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ElMessage.error("发布失败")
|
||||
return
|
||||
ElMessage.success("发布文章成功")
|
||||
openAddarticlesModal.value = false
|
||||
getarticles()
|
||||
}
|
||||
catch (error){
|
||||
console.log(error)
|
||||
ElMessage.error("发布文章失败")
|
||||
}
|
||||
editor.value.clearContent()
|
||||
title.value = ""
|
||||
}
|
||||
|
||||
const openDetails = (row) => {
|
||||
console.log(row)
|
||||
// 打开文章详情页面
|
||||
articleinfo.setArticle(row) // 设置文章详情
|
||||
detail.setType("article")
|
||||
// 跳转到文章详情页面
|
||||
router.push('/admin/details')
|
||||
|
||||
const update = async () => {
|
||||
console.log(userinfo.token)
|
||||
try{
|
||||
const response = await axios.post("/api/admin/update/article", {
|
||||
id: id.value,
|
||||
title: title.value,
|
||||
content: editor2.value.getContent(),
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${userinfo.token}`,
|
||||
}
|
||||
})
|
||||
if (response.data.code !== 200) {
|
||||
ElMessage.error(response.data.message)
|
||||
return
|
||||
}
|
||||
ElMessage.success("更新文章成功")
|
||||
openEditarticlesModal.value = false
|
||||
getarticles()
|
||||
}
|
||||
catch (error){
|
||||
console.log(error)
|
||||
ElMessage.error("更新文章失败")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
page.value = 1
|
||||
getArticle()
|
||||
getarticles()
|
||||
})
|
||||
|
||||
</script>
|
||||
@@ -8,12 +8,11 @@
|
||||
</template>
|
||||
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="n_title" label="标题" />
|
||||
<el-table-column prop="title" label="标题" />
|
||||
<el-table-column prop="published" label="发布时间" />
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="openDetails(scope.row)">查看</el-button>
|
||||
<el-button size="small">编辑</el-button>
|
||||
<el-button size="small" @click="edit(scope)">编辑</el-button>
|
||||
<el-button size="small" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -21,10 +20,16 @@
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="openAddNewsModal" title="新增新闻" style="height: 70%; width: 80%;">
|
||||
<el-input size="large" v-model="title" prefix-icon="el-icon-edit" placeholder="请输入文章标题"></el-input>
|
||||
<MarkdownEditor ref="editor" />
|
||||
<el-input size="large" v-model=title prefix-icon="el-icon-edit" placeholder="请输入文章标题"></el-input>
|
||||
<MarkdownEditor ref="editor1" @ready="editor1ready" />
|
||||
<el-button type="primary" @click="submit()">发布</el-button>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="openEditNewsModal" title="编辑新闻" style="height: 70%; width: 80%;">
|
||||
<el-input size="large" v-model=title prefix-icon="el-icon-edit" placeholder="请输入文章标题"></el-input>
|
||||
<MarkdownEditor ref="editor2" @ready="editor2ready" />
|
||||
<el-button type="primary" @click="update()">更新</el-button>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -32,27 +37,46 @@ import { userInfoStore } from '@/store/store'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import axios from 'axios'
|
||||
import { newsStore, detailsStore } from '@/store/details'
|
||||
import { useRouter } from 'vue-router'
|
||||
import MarkdownEditor from '@/components/MarkdownEditor.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const newsinfo = newsStore()
|
||||
const detailtype = detailsStore()
|
||||
const userinfo = userInfoStore()
|
||||
|
||||
const openEditNewsModal =ref(false)
|
||||
const openAddNewsModal = ref(false)
|
||||
|
||||
const id = ref('')
|
||||
const title = ref('')
|
||||
const content = ref('')
|
||||
|
||||
const page = ref(1)
|
||||
const pageSize = ref(5)
|
||||
const total = ref()
|
||||
|
||||
const editor1 = ref(null)
|
||||
const editor2 = ref(null)
|
||||
|
||||
const tableData = ref([])
|
||||
|
||||
const edit = (scope) => {
|
||||
openEditNewsModal.value = true
|
||||
id.value = scope.row.id
|
||||
title.value = scope.row.title
|
||||
content.value = scope.row.content
|
||||
}
|
||||
|
||||
|
||||
const editor1ready = () =>{
|
||||
title.value = ''
|
||||
editor1.value.setContent('')
|
||||
}
|
||||
|
||||
const editor2ready = () =>{
|
||||
editor2.value.setContent(content.value)
|
||||
}
|
||||
|
||||
const getNews = async () => {
|
||||
try {
|
||||
const response = await axios.get("/api/admin/get/news", {
|
||||
const response = await axios.get("/api/blog/get/news", {
|
||||
headers: {
|
||||
Authorization: "Bearer " + userinfo.token,
|
||||
},
|
||||
@@ -73,20 +97,55 @@ const getNews = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const openDetails = (row) => {
|
||||
console.log(row)
|
||||
// 打开文章详情页面
|
||||
newsinfo.setNews(row) // 设置文章详情
|
||||
detailtype.setType("news")
|
||||
// 跳转到文章详情页面
|
||||
router.push('/admin/details')
|
||||
}
|
||||
|
||||
|
||||
const submit = async () => {
|
||||
|
||||
|
||||
try{
|
||||
const response = await axios.post("/api/admin/add/news", {
|
||||
title: title.value,
|
||||
content: editor1.value.getContent(),
|
||||
})
|
||||
if (response.data.code !== 200) {
|
||||
ElMessage.error(response.data.message)
|
||||
return
|
||||
}
|
||||
ElMessage.success("发布新闻成功")
|
||||
openAddNewsModal.value = false
|
||||
getNews()
|
||||
}
|
||||
catch (error){
|
||||
console.log(error)
|
||||
ElMessage.error("发布新闻失败")
|
||||
}
|
||||
}
|
||||
|
||||
const update = async () => {
|
||||
console.log(userinfo.token)
|
||||
try{
|
||||
const response = await axios.post("/api/admin/update/news", {
|
||||
id: id.value,
|
||||
title: title.value,
|
||||
content: editor2.value.getContent(),
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${userinfo.token}`,
|
||||
}
|
||||
})
|
||||
if (response.data.code !== 200) {
|
||||
ElMessage.error(response.data.message)
|
||||
return
|
||||
}
|
||||
ElMessage.success("更新新闻成功")
|
||||
openEditNewsModal.value = false
|
||||
getNews()
|
||||
}
|
||||
catch (error){
|
||||
console.log(error)
|
||||
ElMessage.error("更新新闻失败")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
page.value = 1
|
||||
getNews()
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span>文章列表</span>
|
||||
<el-button type="primary">新增文章</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="p_name" label="项目名称" />
|
||||
<el-table-column prop="techstack" label="技术栈" />
|
||||
<el-table-column prop="p_status" label="项目状态" />
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button size="small">查看</el-button>
|
||||
<el-button size="small">编辑</el-button>
|
||||
<el-button size="small" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { userInfoStore } from '@/store/store'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
const userinfo = userInfoStore()
|
||||
|
||||
const page = ref(1)
|
||||
const pageSize = ref(5)
|
||||
const total = ref()
|
||||
|
||||
const tableData = ref([])
|
||||
|
||||
const getProject = async () => {
|
||||
try {
|
||||
const response = await axios.get("/api/admin/get/projects", {
|
||||
headers: {
|
||||
Authorization: "Bearer " + userinfo.token,
|
||||
},
|
||||
params: {
|
||||
current: page.value,
|
||||
size: pageSize.value
|
||||
}
|
||||
})
|
||||
if (!response.data.code === 200) {
|
||||
ElMessage.error(response.data.message)
|
||||
return
|
||||
}
|
||||
tableData.value = response.data.data.records
|
||||
total.value = response.data.data.total
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ElMessage.error("获取文章失败")
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
page.value = 1
|
||||
getProject()
|
||||
})
|
||||
|
||||
</script>
|
||||
@@ -20,12 +20,12 @@
|
||||
</el-row>
|
||||
<el-row style="height: 60%;">
|
||||
<el-col :span="24" style="height: 100%;">
|
||||
<div class="news" v-for="item in news" @click="openDetails(item.a_id)">
|
||||
<div class="newspic">
|
||||
<div class="articles" v-for="item in articles" @click="openDetails(item)">
|
||||
<div class="articlespic">
|
||||
<img :src="item.pic" alt="芜湖" />
|
||||
</div>
|
||||
<div class="newscontent">
|
||||
<h2>{{ item.n_title }}</h2>
|
||||
<div class="articlescontent">
|
||||
<h2>{{ item.title }}</h2>
|
||||
<p class="date">{{ item.published }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,65 +54,18 @@ const search_text = ref('')
|
||||
|
||||
const pageSize = 5
|
||||
const page = 1
|
||||
const news = ref([
|
||||
{
|
||||
a_id: '1',
|
||||
n_title: '1',
|
||||
synopsis: '1',
|
||||
published: '1',
|
||||
pic: '1'
|
||||
},
|
||||
{
|
||||
a_id: '2',
|
||||
n_title: '2',
|
||||
synopsis: '2',
|
||||
published: '2',
|
||||
pic: '2'
|
||||
},
|
||||
{
|
||||
a_id: '3',
|
||||
n_title: '3',
|
||||
synopsis: '3',
|
||||
published: '3',
|
||||
pic: '3'
|
||||
},
|
||||
{
|
||||
a_id: '1',
|
||||
n_title: '1',
|
||||
synopsis: '1',
|
||||
published: '1',
|
||||
pic: '1'
|
||||
},
|
||||
{
|
||||
a_id: '2',
|
||||
n_title: '2',
|
||||
synopsis: '2',
|
||||
published: '2',
|
||||
pic: '2'
|
||||
},
|
||||
{
|
||||
a_id: '3',
|
||||
n_title: '3',
|
||||
synopsis: '3',
|
||||
published: '3',
|
||||
pic: '3'
|
||||
},
|
||||
const articles = ref([])
|
||||
|
||||
])
|
||||
|
||||
const getNews = async () => {
|
||||
const getArticles = async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/blog/get/news', {
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + userinfo.token
|
||||
},
|
||||
const response = await axios.get('/api/blog/get/articles', {
|
||||
params: {
|
||||
current: page,
|
||||
size: pageSize
|
||||
}
|
||||
})
|
||||
if (response.data.code === 200) {
|
||||
news.value = response.data.data.records
|
||||
articles.value = response.data.data.records
|
||||
} else {
|
||||
console.log(response.data.message)
|
||||
return
|
||||
@@ -124,31 +77,15 @@ const getNews = async () => {
|
||||
|
||||
}
|
||||
|
||||
const openDetails = async (a_id) => {
|
||||
// const response = await axios.get('/api/blog/get/article/' + a_id, {
|
||||
// headers: {
|
||||
// Authorization: 'Bearer ' + userinfo.token
|
||||
// }
|
||||
// })
|
||||
// if (!response.data.code === 200) {
|
||||
// console.log(response.data.message)
|
||||
// return
|
||||
// }
|
||||
// details.setViewDetails(response.data.data)
|
||||
details.setViewDetails({
|
||||
id: "1212",
|
||||
title: "12312",
|
||||
content: "231323",
|
||||
created: "123123",
|
||||
updated: "123132",
|
||||
})
|
||||
const openDetails = async (item) => {
|
||||
details.setViewDetails(item)
|
||||
router.push('viewDetails')
|
||||
}
|
||||
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
getNews()
|
||||
getArticles()
|
||||
|
||||
})
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
<!-- 用户登录、注册弹窗 -->
|
||||
<el-dialog title="用户登录" v-model="loginDialog" style="min-width: 400px; max-width: 500px;">
|
||||
<el-form :model="loginInfo" label-width="auto" style="width: 100%;" :rules="isadmin ? null : rules">
|
||||
<el-form-item label="账号or邮箱" prop="u_account">
|
||||
<el-input v-model="loginInfo.u_account"></el-input>
|
||||
<el-form-item label="账号or邮箱" prop="account">
|
||||
<el-input v-model="loginInfo.account"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="u_password">
|
||||
<el-input v-model="loginInfo.u_password" type="password"></el-input>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="loginInfo.password" type="password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="isadmin">管理员登录</el-checkbox>
|
||||
@@ -54,14 +54,14 @@
|
||||
|
||||
<el-dialog title="用户注册" v-model="registDialog" style="min-width: 400px; max-width: 500px;">
|
||||
<el-form ref="formRef" :model="loginInfo" label-width="auto" style="width: 100%;" :rules="rules">
|
||||
<el-form-item label="邮箱" prop="u_account">
|
||||
<el-input v-model="loginInfo.u_account"></el-input>
|
||||
<el-form-item label="邮箱" prop="account">
|
||||
<el-input v-model="loginInfo.account"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="u_password">
|
||||
<el-input v-model="loginInfo.u_password" type="password"></el-input>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="loginInfo.password" type="password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="u_password_confirm">
|
||||
<el-input v-model="loginInfo.u_password_confirm" type="password"></el-input>
|
||||
<el-form-item label="确认密码" prop="password_confirm">
|
||||
<el-input v-model="loginInfo.password_confirm" type="password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码" prop="code">
|
||||
<el-input v-model="loginInfo.code" style="width: 50%; margin-right: 10px" />
|
||||
@@ -81,7 +81,6 @@
|
||||
<script setup>
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import SHA256 from 'crypto-js/sha256';
|
||||
import { userInfoStore } from '@/store/store';
|
||||
import { getUserInfo } from '@/function/user';
|
||||
import { ElMessage } from 'element-plus';
|
||||
@@ -103,9 +102,9 @@ const router = useRouter(); // 获取路由实例
|
||||
const formRef = ref(null); // 用于表单验证的引用
|
||||
|
||||
const loginInfo = reactive({
|
||||
u_account: '',
|
||||
u_password: '',
|
||||
u_password_confirm: '',
|
||||
account: '',
|
||||
password: '',
|
||||
password_confirm: '',
|
||||
code_id: '',
|
||||
code: ''
|
||||
})
|
||||
@@ -115,19 +114,19 @@ const countdown = ref(0);
|
||||
let timer = null;
|
||||
|
||||
const rules = reactive({
|
||||
u_account: [
|
||||
account: [
|
||||
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入有效的邮箱地址', trigger: ['blur', 'change'] }
|
||||
],
|
||||
u_password: [
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '密码长度必须在6到20个字符之间', trigger: 'blur' }
|
||||
],
|
||||
u_password_confirm: [
|
||||
password_confirm: [
|
||||
{ required: true, message: '请确认密码', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value !== loginInfo.u_password) {
|
||||
if (value !== loginInfo.password) {
|
||||
callback(new Error('两次输入的密码不一致'));
|
||||
} else {
|
||||
callback();
|
||||
@@ -170,7 +169,7 @@ watch(route, () => {
|
||||
});
|
||||
|
||||
const blogLogin = () => {
|
||||
if (u_name.value == 'admin') {
|
||||
if (userinfo.user.role == 'admin') {
|
||||
const origin = window.location.origin
|
||||
const redirect_uri = `${origin}/admin`
|
||||
window.open(redirect_uri, '_blank')
|
||||
@@ -200,39 +199,38 @@ const submitForm = () => {
|
||||
}
|
||||
|
||||
const login = async () => {
|
||||
hashpassword.value = SHA256(loginInfo.u_password).toString();
|
||||
// console.log(hashpassword.value)
|
||||
if (isadmin.value) {
|
||||
const response = await axios.post('/api/admin/login', {
|
||||
u_account: loginInfo.u_account,
|
||||
u_password: hashpassword.value
|
||||
const response = await axios.post('/api/login', {
|
||||
account: loginInfo.account,
|
||||
password: loginInfo.password
|
||||
})
|
||||
if (!response.data.code == 200) {
|
||||
ElMessage.error(response.data.message)
|
||||
return
|
||||
} else if (response.data.data.role !== 'Admin') {
|
||||
} else if (response.data.data.role !== 'admin') {
|
||||
ElMessage.error('不是管理员,请联系站长')
|
||||
return
|
||||
} else {
|
||||
userinfo.token = response.data.data.token
|
||||
userinfo.user.u_account = loginInfo.u_account
|
||||
userinfo.user.account = loginInfo.account
|
||||
loginDialog.value = false;
|
||||
getUserInfo();
|
||||
u_name.value = userinfo.user.u_name
|
||||
userinfo.user.name = response.data.data.userInfo.name
|
||||
userinfo.user.role = response.data.data.role
|
||||
u_name.value = userinfo.user.name
|
||||
const origin = window.location.origin
|
||||
const redirect_uri = `${origin}/admin`
|
||||
window.open(redirect_uri, '_blank')
|
||||
}
|
||||
} else {
|
||||
const response = await axios.post('/api/login', {
|
||||
u_account: loginInfo.u_account,
|
||||
u_password: hashpassword.value
|
||||
account: loginInfo.account,
|
||||
password: loginInfo.password
|
||||
}).then((response) => {
|
||||
console.log(response.data);
|
||||
if (response.data.code == 200) {
|
||||
userinfo.token = response.data.data.token;
|
||||
getUserInfo();
|
||||
u_name.value = response.data.u_name;
|
||||
userinfo.user.name = response.data.data.userInfo.name
|
||||
u_name.value = userinfo.user.name
|
||||
loginDialog.value = false;
|
||||
ElMessage.success('登录成功');
|
||||
} else {
|
||||
@@ -262,7 +260,7 @@ const getCode = async () => {
|
||||
if (countdown.value > 0) return
|
||||
|
||||
// 此处调用你的发送验证码接口逻辑
|
||||
// 例如 axios.post('/api/code', { email: loginInfo.value.u_account })
|
||||
// 例如 axios.post('/api/code', { email: loginInfo.value.account })
|
||||
|
||||
// 成功后开始倒计时
|
||||
startCountdown()
|
||||
@@ -358,8 +356,8 @@ const getCode = async () => {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
/* .login-btn {
|
||||
display: none;
|
||||
}
|
||||
} */
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,19 @@
|
||||
<template>
|
||||
<div>me</div>
|
||||
<el-buton type="primary" @click="logout">
|
||||
退出登录
|
||||
</el-buton>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import {userInfoStore} from "@/store/store";
|
||||
|
||||
const userinfo = userInfoStore();
|
||||
|
||||
const logout = () => {
|
||||
userinfo.clearUserInfo();
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
@@ -20,12 +20,12 @@
|
||||
</el-row>
|
||||
<el-row style="height: 60%;">
|
||||
<el-col :span="24" style="height: 100%;">
|
||||
<div class="news" v-for="item in news" @click="openDetails(item.a_id)">
|
||||
<div class="news" v-for="item in news" @click="openDetails(item)">
|
||||
<div class="newspic">
|
||||
<img :src="item.pic" alt="芜湖" />
|
||||
</div>
|
||||
<div class="newscontent">
|
||||
<h2>{{ item.n_title }}</h2>
|
||||
<h2>{{ item.title }}</h2>
|
||||
<p class="date">{{ item.published }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,51 +67,7 @@ const search_text = ref('')
|
||||
|
||||
const pageSize = 5
|
||||
const page = 1
|
||||
const news = ref([
|
||||
{
|
||||
a_id: '1',
|
||||
n_title: '1',
|
||||
synopsis: '1',
|
||||
published: '1',
|
||||
pic: '1'
|
||||
},
|
||||
{
|
||||
a_id: '2',
|
||||
n_title: '2',
|
||||
synopsis: '2',
|
||||
published: '2',
|
||||
pic: '2'
|
||||
},
|
||||
{
|
||||
a_id: '3',
|
||||
n_title: '3',
|
||||
synopsis: '3',
|
||||
published: '3',
|
||||
pic: '3'
|
||||
},
|
||||
{
|
||||
a_id: '1',
|
||||
n_title: '1',
|
||||
synopsis: '1',
|
||||
published: '1',
|
||||
pic: '1'
|
||||
},
|
||||
{
|
||||
a_id: '2',
|
||||
n_title: '2',
|
||||
synopsis: '2',
|
||||
published: '2',
|
||||
pic: '2'
|
||||
},
|
||||
{
|
||||
a_id: '3',
|
||||
n_title: '3',
|
||||
synopsis: '3',
|
||||
published: '3',
|
||||
pic: '3'
|
||||
},
|
||||
|
||||
])
|
||||
const news = ref([])
|
||||
|
||||
const dialogWidth = computed(() => {
|
||||
return window.innerWidth < 768 ? '90%' : '60%'
|
||||
@@ -121,7 +77,6 @@ const getNews = async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/blog/get/news', {
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + userinfo.token
|
||||
},
|
||||
params: {
|
||||
current: page,
|
||||
@@ -141,24 +96,8 @@ const getNews = async () => {
|
||||
|
||||
}
|
||||
|
||||
const openDetails = async (a_id) => {
|
||||
// const response = await axios.get('/api/blog/get/article/' + a_id, {
|
||||
// headers: {
|
||||
// Authorization: 'Bearer ' + userinfo.token
|
||||
// }
|
||||
// })
|
||||
// if (!response.data.code === 200) {
|
||||
// console.log(response.data.message)
|
||||
// return
|
||||
// }
|
||||
// details.setViewDetails(response.data.data)
|
||||
details.setViewDetails({
|
||||
id: "1212",
|
||||
title: "12312",
|
||||
content: "231323",
|
||||
created: "123123",
|
||||
updated: "123132",
|
||||
})
|
||||
const openDetails = async (item) => {
|
||||
details.setViewDetails(item)
|
||||
router.push('viewDetails')
|
||||
}
|
||||
|
||||
@@ -166,7 +105,6 @@ const openDetails = async (a_id) => {
|
||||
|
||||
onMounted(() => {
|
||||
getNews()
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<h1>{{ details.detail.title }}</h1>
|
||||
<p style="padding: 20px;">发布时间:{{ details.detail.created }}---更新时间:{{
|
||||
details.detail.updated }}</p>
|
||||
<p style="padding: 20px;">发布时间: {{ details.detail.published }}</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
@@ -17,7 +16,6 @@
|
||||
<div style="width: 100%;">
|
||||
<div v-html="Content" class="markdown-body"></div>
|
||||
</div>
|
||||
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user