@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "YouCo",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"node_modules/@mdi/font": {
|
||||||
|
"version": "7.4.47",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@mdi/font/-/font-7.4.47.tgz",
|
||||||
|
"integrity": "sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
Disclaimer:
|
||||||
|
Hi there, thanks for contributing! Before anything else, please ensure you didn't mean to create an issue on the main MaterialDesign repo instead.
|
||||||
|
If this is intentional, just erase this message. Thanks!
|
@ -0,0 +1,20 @@
|
|||||||
|
Pictogrammers Free License
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
This icon collection is released as free, open source, and GPL friendly by
|
||||||
|
the [Pictogrammers](http://pictogrammers.com/) icon group. You may use it
|
||||||
|
for commercial projects, open source projects, or anything really.
|
||||||
|
|
||||||
|
# Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
Some of the icons are redistributed under the Apache 2.0 license. All other
|
||||||
|
icons are either redistributed under their respective licenses or are
|
||||||
|
distributed under the Apache 2.0 license.
|
||||||
|
|
||||||
|
# Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
All web and desktop fonts are distributed under the Apache 2.0 license. Web
|
||||||
|
and desktop fonts contain some icons that are redistributed under the Apache
|
||||||
|
2.0 license. All other icons are either redistributed under their respective
|
||||||
|
licenses or are distributed under the Apache 2.0 license.
|
||||||
|
|
||||||
|
# Code: MIT (https://opensource.org/licenses/MIT)
|
||||||
|
The MIT license applies to all non-font and non-icon files.
|
@ -0,0 +1,25 @@
|
|||||||
|
> *Note:* Please use the main [MaterialDesign](https://github.com/Templarian/MaterialDesign/issues) repo to report issues. This repo is for distribution of the Webfont files only.
|
||||||
|
|
||||||
|
# Webfont - Material Design Icons
|
||||||
|
|
||||||
|
Webfont distribution for the [Material Design Icons](https://materialdesignicons.com).
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install @mdi/font
|
||||||
|
```
|
||||||
|
|
||||||
|
> Package built with [@mdi/font-build](https://github.com/Templarian/MaterialDesign-Font-Build).
|
||||||
|
|
||||||
|
## Related Packages
|
||||||
|
|
||||||
|
[NPM @MDI Organization](https://npmjs.com/org/mdi)
|
||||||
|
|
||||||
|
- JavaScript/Typescript: [MaterialDesign-JS](https://github.com/Templarian/MaterialDesign-JS)
|
||||||
|
- SVG: [MaterialDesign-SVG](https://github.com/Templarian/MaterialDesign-SVG)
|
||||||
|
- Font-Build [MaterialDesign-Font-Build](https://github.com/Templarian/MaterialDesign-Font-Build)
|
||||||
|
- Desktop Font: [MaterialDesign-Font](https://github.com/Templarian/MaterialDesign-Font)
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
- [MaterialDesignIcons.com](https://materialdesignicons.com)
|
||||||
|
- https://github.com/Templarian/MaterialDesign
|
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@mdi/font",
|
||||||
|
"version": "7.4.47",
|
||||||
|
"description": "Dist for Material Design Webfont. This includes the Stock and Community icons in a single webfont collection.",
|
||||||
|
"style": "css/materialdesignicons.css",
|
||||||
|
"scripts": {
|
||||||
|
"verify": "node scripts/verify.js",
|
||||||
|
"prepublish": "node scripts/verify.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Templarian/MaterialDesign-Webfont.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"material",
|
||||||
|
"design",
|
||||||
|
"icons",
|
||||||
|
"webfont"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "Austin Andrews",
|
||||||
|
"web": "http://twitter.com/templarian"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/Templarian/MaterialDesign/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://materialdesignicons.com"
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// Parse package.json
|
||||||
|
const packageFile = './package.json';
|
||||||
|
const packageText = fs.readFileSync(packageFile, 'utf8');
|
||||||
|
const packageJson = JSON.parse(packageText);
|
||||||
|
const packageVersion = packageJson.version;
|
||||||
|
// Check for preview.html
|
||||||
|
const previewFile = './preview.html';
|
||||||
|
if (!fs.existsSync(previewFile)) {
|
||||||
|
throw new Error('Error: preview.html must exist!');
|
||||||
|
}
|
||||||
|
const previewText = fs.readFileSync(previewFile, 'utf8');
|
||||||
|
const parts = previewText.match(/<span class="version">([^<]+)<\/span>/);
|
||||||
|
if (parts === null) {
|
||||||
|
// Did you modify preview.html file ???
|
||||||
|
throw new Error('Error: preview.html version string not found!');
|
||||||
|
}
|
||||||
|
// Never include a index.html file!
|
||||||
|
const indexFile = './index.html';
|
||||||
|
if (fs.existsSync(indexFile)) {
|
||||||
|
throw new Error('Error: index.html should not exist, only preview.html');
|
||||||
|
}
|
||||||
|
const previewVersion = parts[1];
|
||||||
|
if (packageVersion != previewVersion) {
|
||||||
|
// Not good, almost published the wrong version
|
||||||
|
throw new Error(`Error: package "${packageVersion}" != preview.html "${previewVersion}"`);
|
||||||
|
}
|
||||||
|
// Verify SCSS Version
|
||||||
|
const scssVariablesFile = './scss/_variables.scss';
|
||||||
|
const scssVariablesText = fs.readFileSync(scssVariablesFile, 'utf8');
|
||||||
|
const vParts = scssVariablesText.match(/"(\d+).(\d+).(\d+)" !default;/);
|
||||||
|
if (vParts === null) {
|
||||||
|
throw new Error('Error: Could not parse SCSS version!');
|
||||||
|
}
|
||||||
|
const scssVersion = `${vParts[1]}.${vParts[2]}.${vParts[3]}`;
|
||||||
|
if (packageVersion != scssVersion) {
|
||||||
|
// Not good, almost published the wrong version
|
||||||
|
throw new Error(`Error: package "${packageVersion}" != scss/variables.scss "${previewVersion}"`);
|
||||||
|
}
|
||||||
|
console.log(`Success: ${packageVersion} looks good!`);
|
@ -0,0 +1,27 @@
|
|||||||
|
// From Font Awesome
|
||||||
|
.#{$mdi-css-prefix}-spin:before {
|
||||||
|
-webkit-animation: #{$mdi-css-prefix}-spin 2s infinite linear;
|
||||||
|
animation: #{$mdi-css-prefix}-spin 2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes #{$mdi-css-prefix}-spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes #{$mdi-css-prefix}-spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
.#{$mdi-css-prefix}:before,
|
||||||
|
.#{$mdi-css-prefix}-set {
|
||||||
|
display: inline-block;
|
||||||
|
font: normal normal normal #{$mdi-font-size-base}/1 '#{$mdi-font-name}'; // shortening font declaration
|
||||||
|
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||||
|
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||||
|
line-height: inherit;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
$mdi-sizes: 18 24 36 48 !default;
|
||||||
|
@each $mdi-size in $mdi-sizes {
|
||||||
|
.#{$mdi-css-prefix}-#{$mdi-size}px {
|
||||||
|
&.#{$mdi-css-prefix}-set,
|
||||||
|
&.#{$mdi-css-prefix}:before {
|
||||||
|
font-size: $mdi-size * 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$mdi-css-prefix}-dark {
|
||||||
|
&:before {
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
}
|
||||||
|
&.#{$mdi-css-prefix}-inactive:before {
|
||||||
|
color: rgba(0, 0, 0, 0.26);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.#{$mdi-css-prefix}-light {
|
||||||
|
&:before {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
&.#{$mdi-css-prefix}-inactive:before {
|
||||||
|
color: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$mdi-degrees: 45 90 135 180 225 270 315 !default;
|
||||||
|
@each $mdi-degree in $mdi-degrees {
|
||||||
|
.#{$mdi-css-prefix}-rotate-#{$mdi-degree}{
|
||||||
|
&:before {
|
||||||
|
-webkit-transform: rotate(#{$mdi-degree}deg);
|
||||||
|
-ms-transform: rotate(#{$mdi-degree}deg);
|
||||||
|
transform: rotate(#{$mdi-degree}deg);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// Not included in production
|
||||||
|
&.#{$mdi-css-prefix}-flip-h:before {
|
||||||
|
-webkit-transform: scaleX(-1) rotate(#{$mdi-degree}deg);
|
||||||
|
transform: scaleX(-1) rotate(#{$mdi-degree}deg);
|
||||||
|
filter: FlipH;
|
||||||
|
-ms-filter: "FlipH";
|
||||||
|
}
|
||||||
|
&.#{$mdi-css-prefix}-flip-v:before {
|
||||||
|
-webkit-transform: scaleY(-1) rotate(#{$mdi-degree}deg);
|
||||||
|
-ms-transform: rotate(#{$mdi-degree}deg);
|
||||||
|
transform: scaleY(-1) rotate(#{$mdi-degree}deg);
|
||||||
|
filter: FlipV;
|
||||||
|
-ms-filter: "FlipV";
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.#{$mdi-css-prefix}-flip-h:before {
|
||||||
|
-webkit-transform: scaleX(-1);
|
||||||
|
transform: scaleX(-1);
|
||||||
|
filter: FlipH;
|
||||||
|
-ms-filter: "FlipH";
|
||||||
|
}
|
||||||
|
.#{$mdi-css-prefix}-flip-v:before {
|
||||||
|
-webkit-transform: scaleY(-1);
|
||||||
|
transform: scaleY(-1);
|
||||||
|
filter: FlipV;
|
||||||
|
-ms-filter: "FlipV";
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
@each $key, $value in $mdi-icons {
|
||||||
|
.#{$mdi-css-prefix}-#{$key}::before {
|
||||||
|
content: char($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$mdi-css-prefix}-blank::before {
|
||||||
|
content: "\F68C";
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: '#{$mdi-font-name}';
|
||||||
|
src: url('#{$mdi-font-path}/#{$mdi-filename}-webfont.eot?v=#{$mdi-version}');
|
||||||
|
src: url('#{$mdi-font-path}/#{$mdi-filename}-webfont.eot?#iefix&v=#{$mdi-version}') format('embedded-opentype'),
|
||||||
|
url('#{$mdi-font-path}/#{$mdi-filename}-webfont.woff2?v=#{$mdi-version}') format('woff2'),
|
||||||
|
url('#{$mdi-font-path}/#{$mdi-filename}-webfont.woff?v=#{$mdi-version}') format('woff'),
|
||||||
|
url('#{$mdi-font-path}/#{$mdi-filename}-webfont.ttf?v=#{$mdi-version}') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
/* MaterialDesignIcons.com */
|
||||||
|
@import "variables";
|
||||||
|
@import "functions";
|
||||||
|
@import "path";
|
||||||
|
@import "core";
|
||||||
|
@import "icons";
|
||||||
|
@import "extras";
|
||||||
|
@import "animated";
|
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "YouCo",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"@mdi/font": "^7.4.47"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mdi/font": {
|
||||||
|
"version": "7.4.47",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@mdi/font/-/font-7.4.47.tgz",
|
||||||
|
"integrity": "sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@mdi/font": "^7.4.47"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "travel-db-migration",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": ""
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "travel-db-migration",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": ""
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
@ -0,0 +1,24 @@
|
|||||||
|
# youco
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"module": "esnext",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"scripthost"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "youco",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": "^3.8.3",
|
||||||
|
"vue": "^2.6.14",
|
||||||
|
"vue-router": "^3.6.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.12.16",
|
||||||
|
"@babel/eslint-parser": "^7.12.16",
|
||||||
|
"@vue/cli-plugin-babel": "~5.0.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||||
|
"@vue/cli-service": "~5.0.0",
|
||||||
|
"eslint": "^7.32.0",
|
||||||
|
"eslint-plugin-vue": "^8.0.3",
|
||||||
|
"vue-template-compiler": "^2.6.14"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "@babel/eslint-parser",
|
||||||
|
"requireConfigFile": false
|
||||||
|
},
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not dead"
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 179 KiB |
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cn">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title>YouCo - 旅行交友新方式</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 2.5 MiB |
After Width: | Height: | Size: 5.5 MiB |
After Width: | Height: | Size: 678 KiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 7.0 MiB |
After Width: | Height: | Size: 626 KiB |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 482 KiB |
After Width: | Height: | Size: 426 KiB |
After Width: | Height: | Size: 200 KiB |
After Width: | Height: | Size: 3.6 MiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 7.4 MiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 761 KiB |
After Width: | Height: | Size: 2.3 MiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.6 MiB |
After Width: | Height: | Size: 8.9 MiB |
@ -0,0 +1,260 @@
|
|||||||
|
<template>
|
||||||
|
<div class="blindbox-result">
|
||||||
|
<div class="result-content">
|
||||||
|
<h2>盲盒交友结果</h2>
|
||||||
|
<div class="user-profile">
|
||||||
|
<div class="profile-header">
|
||||||
|
<img :src="userProfile.avatar" alt="用户头像" class="avatar">
|
||||||
|
<div class="basic-info">
|
||||||
|
<h3>{{ userProfile.name }}, {{ userProfile.age }}岁 ({{ userProfile.gender }})</h3>
|
||||||
|
<p>{{ userProfile.location }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="rating">
|
||||||
|
<span class="rating-text">{{ userProfile.rating.toFixed(1) }}</span>
|
||||||
|
<div class="stars">
|
||||||
|
<span v-for="i in 5" :key="i" :class="{'filled': i <= Math.round(userProfile.rating)}">★</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="profile-details">
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-heart"></i> 爱好</h4>
|
||||||
|
<p>{{ userProfile.hobbies.join(', ') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-airplane"></i> 旅行爱好</h4>
|
||||||
|
<p>{{ userProfile.travelPreferences.join(', ') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-translate"></i> 语言</h4>
|
||||||
|
<p>{{ userProfile.languages.join(', ') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-map-marker"></i> 旅行过的地方</h4>
|
||||||
|
<p>{{ userProfile.traveledPlaces.join(', ') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-bag-personal"></i> 旅行风格</h4>
|
||||||
|
<p>{{ userProfile.travelStyle }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-account-details"></i> 个人简介</h4>
|
||||||
|
<p>{{ userProfile.bio }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-phone"></i> 联系方式</h4>
|
||||||
|
<p v-for="(contact, index) in userProfile.contacts" :key="index">
|
||||||
|
<i :class="contact.icon"></i> {{ contact.type }}: {{ contact.value }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<h4><i class="mdi mdi-calendar-clock"></i> 最近旅行</h4>
|
||||||
|
<p>{{ userProfile.recentTravel.join(' | ') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="reviews">
|
||||||
|
<h4><i class="mdi mdi-comment-text-multiple"></i> 驴友评价</h4>
|
||||||
|
<div v-for="(review, index) in userProfile.reviews" :key="index" class="review-item">
|
||||||
|
<p><strong>{{ review.name }}:</strong> {{ review.comment }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button @click="$emit('close')" class="close-button">关闭</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { userProfiles } from '../data/userProfiles';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BlindboxResult',
|
||||||
|
props: {
|
||||||
|
blindboxData: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
// 随机选择一个用户资料
|
||||||
|
const randomProfile = userProfiles[Math.floor(Math.random() * userProfiles.length)];
|
||||||
|
return {
|
||||||
|
userProfile: randomProfile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.blindbox-result {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-content {
|
||||||
|
background-color: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 20px;
|
||||||
|
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.2);
|
||||||
|
max-width: 800px;
|
||||||
|
width: 95%;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2em;
|
||||||
|
text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
margin-right: 20px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic-info {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic-info h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic-info p {
|
||||||
|
margin: 5px 0;
|
||||||
|
color: #666;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating-text {
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffd700;
|
||||||
|
text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stars {
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-details {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item h4 {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.1em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item h4 i {
|
||||||
|
margin-right: 6px;
|
||||||
|
color: #4a90e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item p {
|
||||||
|
margin: 0;
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reviews {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-item {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-item p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button {
|
||||||
|
background-color: #007AFF;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1em;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加一些装饰性元素 */
|
||||||
|
.result-content::before,
|
||||||
|
.result-content::after {
|
||||||
|
content: '✈';
|
||||||
|
position: absolute;
|
||||||
|
font-size: 2em;
|
||||||
|
color: #4a90e2;
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-content::before {
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
transform: rotate(-30deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-content::after {
|
||||||
|
bottom: 10px;
|
||||||
|
right: 10px;
|
||||||
|
transform: rotate(30deg);
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,191 @@
|
|||||||
|
<template>
|
||||||
|
<div class="matching-animation">
|
||||||
|
<div class="animation-content">
|
||||||
|
<div class="radar-circle"></div>
|
||||||
|
<div class="scanning-line"></div>
|
||||||
|
<div class="matching-text">
|
||||||
|
<span>正在寻找最佳旅伴</span>
|
||||||
|
<div class="dots">
|
||||||
|
<span>.</span>
|
||||||
|
<span>.</span>
|
||||||
|
<span>.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="matching-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">已扫描</span>
|
||||||
|
<span class="value">{{ scannedCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">匹配度</span>
|
||||||
|
<span class="value">{{ matchRate }}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'MatchingAnimation',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
scannedCount: 0,
|
||||||
|
matchRate: 0,
|
||||||
|
animationInterval: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.startAnimation();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
startAnimation() {
|
||||||
|
let count = 0;
|
||||||
|
this.animationInterval = setInterval(() => {
|
||||||
|
count++;
|
||||||
|
this.scannedCount = Math.min(count * 20, 100);
|
||||||
|
this.matchRate = Math.min(count * 25, 98);
|
||||||
|
|
||||||
|
if (count >= 4) {
|
||||||
|
clearInterval(this.animationInterval);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$emit('matchComplete');
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.animationInterval) {
|
||||||
|
clearInterval(this.animationInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.matching-animation {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animation-content {
|
||||||
|
position: relative;
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radar-circle {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
border: 2px solid #4CAF50;
|
||||||
|
border-radius: 50%;
|
||||||
|
position: relative;
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scanning-line {
|
||||||
|
position: absolute;
|
||||||
|
width: 2px;
|
||||||
|
height: 100px;
|
||||||
|
background: linear-gradient(to bottom, #4CAF50, transparent);
|
||||||
|
top: 50px;
|
||||||
|
left: 50%;
|
||||||
|
transform-origin: bottom;
|
||||||
|
animation: scan 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matching-text {
|
||||||
|
margin-top: 30px;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.2em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots span {
|
||||||
|
opacity: 0;
|
||||||
|
animation: dots 1.4s infinite;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots span:nth-child(2) {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots span:nth-child(3) {
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matching-stats {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item .label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item .value {
|
||||||
|
display: block;
|
||||||
|
font-size: 1.4em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.1);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scan {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dots {
|
||||||
|
0%, 20% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,306 @@
|
|||||||
|
<template>
|
||||||
|
<div class="personal-home">
|
||||||
|
<!-- 个人信息头部 -->
|
||||||
|
<div class="profile-header">
|
||||||
|
<div class="profile-cover"></div>
|
||||||
|
<div class="profile-info">
|
||||||
|
<div class="avatar">
|
||||||
|
<img :src="userData.userInfo.avatar" :alt="userData.userInfo.username">
|
||||||
|
</div>
|
||||||
|
<div class="user-details">
|
||||||
|
<h1>{{ userData.userInfo.username }}</h1>
|
||||||
|
<p class="location">
|
||||||
|
<span class="mdi mdi-map-marker"></span>
|
||||||
|
{{ userData.userInfo.location }}
|
||||||
|
</p>
|
||||||
|
<p class="join-date">加入于 {{ userData.userInfo.joinDate }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="level-badge">
|
||||||
|
<span class="mdi mdi-star"></span>
|
||||||
|
Level {{ userData.userInfo.level }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计数据 -->
|
||||||
|
<div class="stats-container">
|
||||||
|
<div class="stat-item" v-for="(value, key) in userData.stats" :key="key">
|
||||||
|
<div class="stat-value">{{ value }}</div>
|
||||||
|
<div class="stat-label">{{ getStatLabel(key) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 成就展示 -->
|
||||||
|
<div class="achievements-section">
|
||||||
|
<h2>我的成就</h2>
|
||||||
|
<div class="achievements-grid">
|
||||||
|
<div
|
||||||
|
v-for="achievement in userData.achievements"
|
||||||
|
:key="achievement.id"
|
||||||
|
class="achievement-card"
|
||||||
|
>
|
||||||
|
<span class="mdi" :class="achievement.icon"></span>
|
||||||
|
<h3>{{ achievement.title }}</h3>
|
||||||
|
<p>{{ achievement.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 旅行记录 -->
|
||||||
|
<div class="travel-history">
|
||||||
|
<h2>旅行足迹</h2>
|
||||||
|
<div class="travel-grid">
|
||||||
|
<div
|
||||||
|
v-for="trip in userData.travelHistory"
|
||||||
|
:key="trip.id"
|
||||||
|
class="trip-card"
|
||||||
|
>
|
||||||
|
<h3>{{ trip.destination }}</h3>
|
||||||
|
<p class="trip-date">{{ formatDate(trip.date) }}</p>
|
||||||
|
<div class="trip-stats">
|
||||||
|
<span><span class="mdi mdi-camera"></span> {{ trip.photos }}</span>
|
||||||
|
<span><span class="mdi mdi-star"></span> {{ trip.rating }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 收藏的目的地 -->
|
||||||
|
<div class="saved-destinations">
|
||||||
|
<h2>收藏的目的地</h2>
|
||||||
|
<div class="destinations-grid">
|
||||||
|
<div
|
||||||
|
v-for="destination in userData.savedDestinations"
|
||||||
|
:key="destination.id"
|
||||||
|
class="destination-card"
|
||||||
|
:style="{ backgroundImage: `url(${destination.imageUrl})` }"
|
||||||
|
>
|
||||||
|
<div class="destination-info">
|
||||||
|
<h3>{{ destination.name }}</h3>
|
||||||
|
<p>{{ destination.type }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { personalHomeData } from '../data/PersonalHome'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PersonalHome',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userData: personalHomeData
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getStatLabel(key) {
|
||||||
|
const labels = {
|
||||||
|
followers: '关注者',
|
||||||
|
following: '关注中',
|
||||||
|
posts: '发布',
|
||||||
|
likes: '获赞'
|
||||||
|
}
|
||||||
|
return labels[key]
|
||||||
|
},
|
||||||
|
formatDate(dateString) {
|
||||||
|
return new Date(dateString).toLocaleDateString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.personal-home {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-header {
|
||||||
|
position: relative;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-cover {
|
||||||
|
height: 200px;
|
||||||
|
background: linear-gradient(135deg, #4a90e2, #87ceeb);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: -60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4px solid white;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-details {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-details h1 {
|
||||||
|
margin: 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location {
|
||||||
|
color: #666;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.join-date {
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-badge {
|
||||||
|
background: #4a90e2;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4a90e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievements-section,
|
||||||
|
.travel-history,
|
||||||
|
.saved-destinations {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin: 20px 0;
|
||||||
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievements-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-card {
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-card .mdi {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #4a90e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.travel-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trip-card {
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trip-stats {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.destinations-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.destination-card {
|
||||||
|
height: 200px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.destination-info {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 20px;
|
||||||
|
background: linear-gradient(transparent, rgba(0,0,0,0.7));
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.destination-info h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.profile-info {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-container {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,355 @@
|
|||||||
|
<template>
|
||||||
|
<div class="settings-page">
|
||||||
|
<div class="settings-container">
|
||||||
|
<!-- 设置页面标题 -->
|
||||||
|
<h1 class="settings-title">账号设置</h1>
|
||||||
|
|
||||||
|
<!-- 设置选项卡 -->
|
||||||
|
<div class="settings-tabs">
|
||||||
|
<button
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.id"
|
||||||
|
:class="['tab-button', { active: activeTab === tab.id }]"
|
||||||
|
@click="activeTab = tab.id"
|
||||||
|
>
|
||||||
|
<span class="mdi" :class="tab.icon"></span>
|
||||||
|
{{ tab.name }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 基本信息设置 -->
|
||||||
|
<div v-if="activeTab === 'profile'" class="settings-section">
|
||||||
|
<h2>个人资料</h2>
|
||||||
|
<div class="form-group">
|
||||||
|
<!-- <label>头像</label> -->
|
||||||
|
<!-- <div class="avatar-upload">
|
||||||
|
<img :src="formData.avatar" alt="用户头像" class="preview-avatar">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
@change="handleAvatarChange"
|
||||||
|
ref="avatarInput"
|
||||||
|
>
|
||||||
|
<button @click="$refs.avatarInput.click()" class="upload-btn">
|
||||||
|
更换头像
|
||||||
|
</button>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>用户名</label>
|
||||||
|
<input type="text" v-model="formData.username">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>所在地</label>
|
||||||
|
<input type="text" v-model="formData.location">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>个人简介</label>
|
||||||
|
<textarea v-model="formData.bio" rows="4"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 账号安全设置 -->
|
||||||
|
<div v-if="activeTab === 'security'" class="settings-section">
|
||||||
|
<h2>账号安全</h2>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>当前密码</label>
|
||||||
|
<input type="password" v-model="formData.currentPassword">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>新密码</label>
|
||||||
|
<input type="password" v-model="formData.newPassword">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>确认新密码</label>
|
||||||
|
<input type="password" v-model="formData.confirmPassword">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 隐私设置 -->
|
||||||
|
<div v-if="activeTab === 'privacy'" class="settings-section">
|
||||||
|
<h2>隐私设置</h2>
|
||||||
|
<div class="switch-group">
|
||||||
|
<label>
|
||||||
|
<span>个人主页可见性</span>
|
||||||
|
<div class="switch">
|
||||||
|
<input type="checkbox" v-model="formData.profileVisible">
|
||||||
|
<span class="slider"></span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="switch-group">
|
||||||
|
<label>
|
||||||
|
<span>允许陌生人私信</span>
|
||||||
|
<div class="switch">
|
||||||
|
<input type="checkbox" v-model="formData.allowMessages">
|
||||||
|
<span class="slider"></span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通知设置 -->
|
||||||
|
<div v-if="activeTab === 'notifications'" class="settings-section">
|
||||||
|
<h2>通知设置</h2>
|
||||||
|
<div class="switch-group">
|
||||||
|
<label>
|
||||||
|
<span>系统通知</span>
|
||||||
|
<div class="switch">
|
||||||
|
<input type="checkbox" v-model="formData.systemNotifications">
|
||||||
|
<span class="slider"></span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="switch-group">
|
||||||
|
<label>
|
||||||
|
<span>私信通知</span>
|
||||||
|
<div class="switch">
|
||||||
|
<input type="checkbox" v-model="formData.messageNotifications">
|
||||||
|
<span class="slider"></span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 保存按钮 -->
|
||||||
|
<div class="settings-actions">
|
||||||
|
<button @click="saveSettings" class="save-button">保存更改</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'UserSettings',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeTab: 'profile',
|
||||||
|
tabs: [
|
||||||
|
{ id: 'profile', name: '个人资料', icon: 'mdi-account' },
|
||||||
|
{ id: 'security', name: '账号安全', icon: 'mdi-shield-lock' },
|
||||||
|
{ id: 'privacy', name: '隐私设置', icon: 'mdi-eye' },
|
||||||
|
{ id: 'notifications', name: '通知设置', icon: 'mdi-bell' }
|
||||||
|
],
|
||||||
|
formData: {
|
||||||
|
avatar: '/assets/images/Person.jpg',
|
||||||
|
username: 'Jackson',
|
||||||
|
location: '天津',
|
||||||
|
bio: '',
|
||||||
|
currentPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
confirmPassword: '',
|
||||||
|
profileVisible: true,
|
||||||
|
allowMessages: true,
|
||||||
|
systemNotifications: true,
|
||||||
|
messageNotifications: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleAvatarChange(event) {
|
||||||
|
const file = event.target.files[0]
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = (e) => {
|
||||||
|
this.formData.avatar = e.target.result
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
saveSettings() {
|
||||||
|
// 这里添加保存设置的逻辑
|
||||||
|
console.log('保存设置:', this.formData)
|
||||||
|
this.$notify({
|
||||||
|
type: 'success',
|
||||||
|
message: '设置已保存'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.settings-page {
|
||||||
|
padding: 40px 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: calc(100vh - 60px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 30px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-title {
|
||||||
|
margin: 0 0 30px;
|
||||||
|
font-size: 24px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-button.active {
|
||||||
|
color: #4a90e2;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section h2 {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input,
|
||||||
|
.form-group textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group textarea {
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-upload {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-avatar {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #4a90e2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-btn:hover {
|
||||||
|
background: #357abd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-group label {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 50px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #ccc;
|
||||||
|
transition: .4s;
|
||||||
|
border-radius: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
left: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
background-color: white;
|
||||||
|
transition: .4s;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider {
|
||||||
|
background-color: #4a90e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider:before {
|
||||||
|
transform: translateX(26px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-actions {
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button {
|
||||||
|
padding: 10px 24px;
|
||||||
|
background: #4a90e2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button:hover {
|
||||||
|
background: #357abd;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="footer-content">
|
||||||
|
<div class="footer-section">
|
||||||
|
<h3>关于我们</h3>
|
||||||
|
<p>旅游交友网致力于为旅行者提供独特的社交体验,让每次旅行都充满乐趣。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-section">
|
||||||
|
<h3>快速链接</h3>
|
||||||
|
<a href="#">使用条款</a>
|
||||||
|
<a href="#">隐私政策</a>
|
||||||
|
<a href="#">常见问题</a>
|
||||||
|
<a href="#">联系我们</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-section">
|
||||||
|
<h3>关注我们</h3>
|
||||||
|
<div class="social-links">
|
||||||
|
<a href="#" class="social-link">
|
||||||
|
<span class="mdi mdi-sina-weibo"></span>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="social-link">
|
||||||
|
<span class="mdi mdi-music-note"></span>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="social-link">
|
||||||
|
<span class="mdi mdi-wechat"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-section">
|
||||||
|
<h3>订阅我们</h3>
|
||||||
|
<div class="subscribe-form">
|
||||||
|
<input type="email" placeholder="您的邮箱" />
|
||||||
|
<button>订阅</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<p>© 2024 旅游交友网 保留所有权利。</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'SiteFooter'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.site-footer {
|
||||||
|
background-color: #2d2d2d;
|
||||||
|
color: #808080;
|
||||||
|
padding: 40px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-content {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
margin: 0 15px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section h3 {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section p {
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section a {
|
||||||
|
color: #808080;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section a:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 40px;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link {
|
||||||
|
color: #808080;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link .mdi {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link:hover {
|
||||||
|
color: #fff;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #404040;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form input::placeholder {
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #4a90e2;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form button:hover {
|
||||||
|
background: #357abd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #404040;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.footer-content {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section {
|
||||||
|
margin: 0 0 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-form button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,89 @@
|
|||||||
|
export const personalHomeData = {
|
||||||
|
// 用户基本信息
|
||||||
|
userInfo: {
|
||||||
|
id: 1,
|
||||||
|
username: "Jackson",
|
||||||
|
avatar: require('@/assets/Person.jpg'),
|
||||||
|
level: 5,
|
||||||
|
joinDate: "2023-01-01",
|
||||||
|
location: "天津"
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户统计数据
|
||||||
|
stats: {
|
||||||
|
followers: 4259741,
|
||||||
|
following: 256,
|
||||||
|
posts: 42,
|
||||||
|
likes: 1547492
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户成就
|
||||||
|
achievements: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "探索达人",
|
||||||
|
icon: "mdi-compass",
|
||||||
|
description: "已探索超过10个城市"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: "社交达人",
|
||||||
|
icon: "mdi-account-group",
|
||||||
|
description: "已结识超过50位好友"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// 用户旅行记录
|
||||||
|
travelHistory: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
destination: "北京",
|
||||||
|
date: "2024-02-15",
|
||||||
|
photos: 12,
|
||||||
|
rating: 4.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
destination: "成都",
|
||||||
|
date: "2024-01-20",
|
||||||
|
photos: 100,
|
||||||
|
rating: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
destination: "天津",
|
||||||
|
date: "2023-01-20",
|
||||||
|
photos: 14,
|
||||||
|
rating: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
destination: "东京",
|
||||||
|
date: "2022-01-20",
|
||||||
|
photos: 21,
|
||||||
|
rating: 0.1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// 用户收藏的目的地
|
||||||
|
savedDestinations: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "成都",
|
||||||
|
type: "幸福之都",
|
||||||
|
imageUrl: require('@/assets/pixian.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "三亚",
|
||||||
|
type: "海滨度假",
|
||||||
|
imageUrl: require('@/assets/sanya.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "丽江",
|
||||||
|
type: "古城文化",
|
||||||
|
imageUrl: require('@/assets/lijiang.png')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
import '@mdi/font/css/materialdesignicons.css'
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
// 添加路由调试
|
||||||
|
router.afterEach((to, from) => {
|
||||||
|
console.log('Route changed:', {
|
||||||
|
from: from.path,
|
||||||
|
to: to.path
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app')
|
@ -0,0 +1,67 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueRouter from 'vue-router'
|
||||||
|
import PersonalHome from '../components/PersonalHome.vue'
|
||||||
|
import UserSettings from '../components/Settings.vue'
|
||||||
|
import HelpCenter from '../components/Help.vue'
|
||||||
|
import LoginPage from '../components/LoginPage.vue' // 添加这行
|
||||||
|
|
||||||
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect: '/discover'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/personal-home',
|
||||||
|
name: 'PersonalHome',
|
||||||
|
component: PersonalHome
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings',
|
||||||
|
name: 'UserSettings',
|
||||||
|
component: UserSettings
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/help',
|
||||||
|
name: 'HelpCenter',
|
||||||
|
component: HelpCenter
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
name: 'Login',
|
||||||
|
component: LoginPage
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: 'history',
|
||||||
|
base: process.env.BASE_URL,
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理路由错误
|
||||||
|
const originalPush = VueRouter.prototype.push
|
||||||
|
VueRouter.prototype.push = function push(location) {
|
||||||
|
return originalPush.call(this, location).catch(err => {
|
||||||
|
if (err.name !== 'NavigationDuplicated') {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/* // 添加导航守卫
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true'
|
||||||
|
|
||||||
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
|
if (!isLoggedIn) {
|
||||||
|
next('/login')
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}) */
|
||||||
|
|
||||||
|
export default router
|
@ -0,0 +1,4 @@
|
|||||||
|
const { defineConfig } = require('@vue/cli-service')
|
||||||
|
module.exports = defineConfig({
|
||||||
|
transpileDependencies: true
|
||||||
|
})
|
@ -1 +0,0 @@
|
|||||||
src
|
|