init
2
.browserslistrc
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
> 1%
|
||||||
|
last 2 versions
|
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2019 diaogroup
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
20
README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# 曳光控制台
|
||||||
|
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
5
babel.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
12007
package-lock.json
generated
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "ygadmin",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"buildsuper": "vue-cli-service build --modern"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"core-js": "^3.6.4",
|
||||||
|
"crc-32": "^1.2.0",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
|
"lrz": "^4.9.40",
|
||||||
|
"material-design-icons": "^3.0.1",
|
||||||
|
"register-service-worker": "^1.6.2",
|
||||||
|
"roboto-fontface": "^0.6.0",
|
||||||
|
"vconsole": "^3.3.4",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-clipboard2": "^0.3.1",
|
||||||
|
"vue-material": "^1.0.0-beta-11",
|
||||||
|
"vue-router": "^3.1.5",
|
||||||
|
"vue-svg-icon": "^1.2.9",
|
||||||
|
"vue-touch": "^2.0.0-beta.4",
|
||||||
|
"vuex": "^3.1.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "^4.2.0",
|
||||||
|
"@vue/cli-plugin-pwa": "^4.2.0",
|
||||||
|
"@vue/cli-plugin-router": "^4.2.0",
|
||||||
|
"@vue/cli-plugin-vuex": "^4.2.0",
|
||||||
|
"@vue/cli-service": "^4.2.0",
|
||||||
|
"node-sass": "^4.12.0",
|
||||||
|
"sass-loader": "^8.0.2",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
public/img/icons/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
public/img/icons/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
public/img/icons/apple-touch-icon-120x120.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
public/img/icons/apple-touch-icon-152x152.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
public/img/icons/apple-touch-icon-180x180.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
public/img/icons/apple-touch-icon-60x60.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/img/icons/apple-touch-icon-76x76.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
public/img/icons/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
public/img/icons/favicon-16x16.png
Normal file
After Width: | Height: | Size: 387 B |
BIN
public/img/icons/favicon-32x32.png
Normal file
After Width: | Height: | Size: 726 B |
BIN
public/img/icons/msapplication-icon-144x144.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
public/img/icons/mstile-150x150.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
1
public/img/icons/safari-pinned-tab.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1582191167349" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3270" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M921.6 716.75904L415.46752 210.66752a136.25344 136.25344 0 0 0-96.54272-39.99744c-70.93248 0-128.53248 54.272-135.19872 123.43296L102.4 375.43936h86.12864C210.59584 506.39872 294.57408 616.09984 409.6 673.49504v179.84512h68.27008V700.34432a405.18656 405.18656 0 0 0 68.25984 13.70112v139.30496H614.4V716.75904h307.2zM448.93184 340.6336L620.2368 511.95904h-39.95648c-75.27424 0-136.54016-61.22496-136.54016-136.52992-0.01024-12.12416 2.12992-23.63392 5.19168-34.79552z m-198.26688-33.46432a68.32128 68.32128 0 0 1 68.25984-68.22912c18.19648 0 35.36896 7.09632 48.27136 19.99872l28.4672 28.4672a202.37312 202.37312 0 0 0-20.20352 88.03328c0 112.92672 91.86304 204.8 204.8 204.8h108.22656l68.27008 68.25984H592.00512c-188.20096 0-341.34016-153.1392-341.34016-341.32992z" p-id="3271" fill="#bbdefb"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
38
public/index.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<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>曳光</title>
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<link rel="apple-touch-icon-precomposed" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<meta itemprop="name" content="曳光控制台" />
|
||||||
|
<!-- 描述 -->
|
||||||
|
<meta itemprop="description" content="负责进行曳光内容审核" />
|
||||||
|
<!-- 图片 -->
|
||||||
|
<meta itemprop="image" content="http://canary.moe/img/canary.png" />
|
||||||
|
<script>
|
||||||
|
try {
|
||||||
|
console.log('%cRainSun Copyright \xa9 2019-%s',
|
||||||
|
'font-size:12px;color:#999999;', (new Date).getFullYear());
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</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>
|
2
public/robots.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow:
|
205
src/App.vue
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<icon class="bg" name="canary"></icon>
|
||||||
|
<!-- 缓存 -->
|
||||||
|
<keep-alive>
|
||||||
|
<router-view v-if="this.$route.meta.keepAlive"></router-view>
|
||||||
|
</keep-alive>
|
||||||
|
<!-- 非缓存 -->
|
||||||
|
<router-view v-if="!this.$route.meta.keepAlive"></router-view>
|
||||||
|
<md-bottom-bar
|
||||||
|
style="position: fixed; bottom: 0; left: 0; width: 100%;"
|
||||||
|
md-sync-route
|
||||||
|
v-if="bar_state"
|
||||||
|
>
|
||||||
|
<md-bottom-bar-item
|
||||||
|
id="bottom-bar-item-home"
|
||||||
|
md-icon="home"
|
||||||
|
md-label="主页"
|
||||||
|
to="/home"
|
||||||
|
></md-bottom-bar-item>
|
||||||
|
<md-bottom-bar-item
|
||||||
|
id="bottom-bar-item-create"
|
||||||
|
md-icon="near_me"
|
||||||
|
md-label="创建"
|
||||||
|
to="/create"
|
||||||
|
></md-bottom-bar-item>
|
||||||
|
<md-bottom-bar-item
|
||||||
|
id="bottom-bar-item-mine"
|
||||||
|
md-icon="person"
|
||||||
|
md-label="我的"
|
||||||
|
to="/account"
|
||||||
|
></md-bottom-bar-item>
|
||||||
|
</md-bottom-bar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
computed: {
|
||||||
|
...mapState(["bar_state"])
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
@import "./style/main";
|
||||||
|
@import "./style/font";
|
||||||
|
@import "~vue-material/dist/theme/engine";
|
||||||
|
@import "~vue-material/dist/theme/all";
|
||||||
|
body,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
hr,
|
||||||
|
p,
|
||||||
|
blockquote,
|
||||||
|
dl,
|
||||||
|
dt,
|
||||||
|
dd,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
li,
|
||||||
|
pre,
|
||||||
|
form,
|
||||||
|
fieldset,
|
||||||
|
legend,
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
body,
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font: 12px/1.5tahoma, arial, \5b8b\4f53;
|
||||||
|
}
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
address,
|
||||||
|
cite,
|
||||||
|
dfn,
|
||||||
|
em,
|
||||||
|
var {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
pre,
|
||||||
|
samp {
|
||||||
|
font-family: couriernew, courier, monospace;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
sup {
|
||||||
|
vertical-align: text-top;
|
||||||
|
}
|
||||||
|
sub {
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
legend {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
fieldset,
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
@include set-theme-dark();
|
||||||
|
@import "~vue-material/dist/theme/all";
|
||||||
|
.md-caption {
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html[data-theme="light"] {
|
||||||
|
@include set-theme-light();
|
||||||
|
@import "~vue-material/dist/theme/all";
|
||||||
|
}
|
||||||
|
#app {
|
||||||
|
font-family: "Roboto", "Helvetica Neue", Helvetica, "PingFang SC",
|
||||||
|
"Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
/* text-align: center; */
|
||||||
|
// color: #2c3e50;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.bg {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
z-index: -100;
|
||||||
|
height: 5rem;
|
||||||
|
width: 5rem;
|
||||||
|
margin-top: -2.5rem;
|
||||||
|
margin-left: -2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
.md-autocomplete-box-content {
|
||||||
|
left: 0.2rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#__vconsole {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vconsole-show {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-bottom-bar.md-type-fixed .md-bottom-bar-item {
|
||||||
|
max-width: 1000px !important;
|
||||||
|
}
|
||||||
|
</style>
|
BIN
src/assets/KFOmCnqEu92Fr1Mu4WxKOzY.woff2
Normal file
BIN
src/assets/MaterialIcons-Regular.eot
Normal file
BIN
src/assets/MaterialIcons-Regular.ttf
Normal file
BIN
src/assets/MaterialIcons-Regular.woff
Normal file
BIN
src/assets/MaterialIcons-Regular.woff2
Normal file
BIN
src/assets/canary.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/logo.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
23
src/axios/fetch.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export const api = axios.create({
|
||||||
|
baseURL: 'https://yg.canary.moe/v1/user/',
|
||||||
|
// baseURL: window.location.origin + '/api/',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*'
|
||||||
|
},
|
||||||
|
timeout: 30 * 1000
|
||||||
|
})
|
||||||
|
|
||||||
|
//设置拦截器
|
||||||
|
api.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
// console.log('拦截器:请求成功', response)
|
||||||
|
return response
|
||||||
|
}, (error) => {
|
||||||
|
// console.log('拦截器:发生错误', error.response)
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
40
src/main.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import './registerServiceWorker'
|
||||||
|
import router from './router'
|
||||||
|
import store from './store'
|
||||||
|
import { setHtmlFontSize } from './utils/px2rem.js'
|
||||||
|
// icon-loader
|
||||||
|
import Icon from 'vue-svg-icon/Icon.vue'
|
||||||
|
Vue.component('icon', Icon);
|
||||||
|
|
||||||
|
// material
|
||||||
|
import VueMaterial from 'vue-material'
|
||||||
|
import 'vue-material/dist/vue-material.min.css'
|
||||||
|
import 'vue-material/dist/theme/default.css'
|
||||||
|
// import 'vue-material/dist/theme/default-dark.css'
|
||||||
|
import 'material-design-icons/iconfont/material-icons.css'
|
||||||
|
Vue.use(VueMaterial)
|
||||||
|
|
||||||
|
//px2rem
|
||||||
|
setHtmlFontSize();
|
||||||
|
|
||||||
|
// 剪切板
|
||||||
|
import VueClipboard from "vue-clipboard2";
|
||||||
|
Vue.use(VueClipboard);
|
||||||
|
|
||||||
|
// 手势控件
|
||||||
|
var VueTouch = require('vue-touch')
|
||||||
|
Vue.use(VueTouch, {name: 'v-touch'})
|
||||||
|
|
||||||
|
// vconsole
|
||||||
|
import Vconsole from 'vconsole';
|
||||||
|
new Vconsole();
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app')
|
33
src/registerServiceWorker.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
|
import { register } from 'register-service-worker'
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||||
|
ready () {
|
||||||
|
console.log(
|
||||||
|
'App is being served from cache by a service worker.\n' +
|
||||||
|
'For more details, visit https://goo.gl/AFskqB'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
registered () {
|
||||||
|
console.log('Service worker has been registered.')
|
||||||
|
},
|
||||||
|
cached () {
|
||||||
|
console.log('Content has been cached for offline use.')
|
||||||
|
},
|
||||||
|
updatefound () {
|
||||||
|
console.log('New content is downloading.')
|
||||||
|
},
|
||||||
|
updated () {
|
||||||
|
console.log('New content is available; please refresh.')
|
||||||
|
window.location.reload(true)
|
||||||
|
},
|
||||||
|
offline () {
|
||||||
|
console.log('No internet connection found. App is running in offline mode.')
|
||||||
|
},
|
||||||
|
error (error) {
|
||||||
|
console.error('Error during service worker registration:', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
53
src/router/index.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueRouter from 'vue-router'
|
||||||
|
|
||||||
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/home',
|
||||||
|
name: 'Home',
|
||||||
|
component: () => import(/* webpackChunkName: "verify" */ '../views/Home/Home.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/create',
|
||||||
|
name: 'Create',
|
||||||
|
component: () => import(/* webpackChunkName: "create" */ '../views/Create/Create.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account',
|
||||||
|
name: 'Account',
|
||||||
|
component: () => import(/* webpackChunkName: "account" */ '../views/Account/Account.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/detail',
|
||||||
|
name: 'Detail',
|
||||||
|
component: () => import(/* webpackChunkName: "detail" */ '../views/Detail/Detail.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '*', // 页面不存在的情况下会跳到home
|
||||||
|
redirect: '/home',
|
||||||
|
name: 'notFound',
|
||||||
|
hidden: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: 'history',
|
||||||
|
base: process.env.BASE_URL,
|
||||||
|
routes,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
69
src/store/index.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
state: {
|
||||||
|
// 用户信息
|
||||||
|
user_info: {},
|
||||||
|
// 配置信息
|
||||||
|
settings: {
|
||||||
|
open_vconsole: false,
|
||||||
|
is_dark_mode: false,
|
||||||
|
},
|
||||||
|
// 失物招领信息
|
||||||
|
laf: [],
|
||||||
|
// bottomBar显示状态
|
||||||
|
bar_state: true
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
// 设置用户信息
|
||||||
|
SET_USERINFO(state, user_info) {
|
||||||
|
state.user_info = user_info;
|
||||||
|
},
|
||||||
|
// 设置配置信息
|
||||||
|
SET_SETTINGS(state, settings) {
|
||||||
|
state.settings = settings;
|
||||||
|
},
|
||||||
|
// 设置失物招领信息
|
||||||
|
SET_LAF(state, laf) {
|
||||||
|
state.laf = laf;
|
||||||
|
},
|
||||||
|
// 设置bottomBar显示状态
|
||||||
|
SET_BARSTATE(state, bar_state) {
|
||||||
|
state.bar_state = bar_state;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
// 设置用户信息
|
||||||
|
setUserInfo({
|
||||||
|
commit
|
||||||
|
}, arg) {
|
||||||
|
commit('SET_USERINFO', arg[0]);
|
||||||
|
localStorage.setItem("storeState", JSON.stringify(arg[1].$store.state));
|
||||||
|
},
|
||||||
|
// 设置配置信息
|
||||||
|
setSettings({
|
||||||
|
commit
|
||||||
|
}, arg) {
|
||||||
|
commit('SET_SETTINGS', arg[0]);
|
||||||
|
localStorage.setItem("storeState", JSON.stringify(arg[1].$store.state));
|
||||||
|
},
|
||||||
|
// 设置失物招领信息
|
||||||
|
setLaf({
|
||||||
|
commit
|
||||||
|
}, arg) {
|
||||||
|
commit('SET_LAF', arg[0]);
|
||||||
|
localStorage.setItem("storeState", JSON.stringify(arg[1].$store.state));
|
||||||
|
},
|
||||||
|
// 设置bottomBar显示状态
|
||||||
|
setBarState({
|
||||||
|
commit
|
||||||
|
}, arg) {
|
||||||
|
commit('SET_BARSTATE', arg[0]);
|
||||||
|
localStorage.setItem("storeState", JSON.stringify(arg[1].$store.state));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
modules: {}
|
||||||
|
})
|
99
src/style/font.scss
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Material Icons';
|
||||||
|
// font-style: normal;
|
||||||
|
// font-weight: 400;
|
||||||
|
// src: url(/assets/MaterialIcons-Regular.eot); /* For IE6-8 */
|
||||||
|
// src: local('Material Icons'),
|
||||||
|
// local('MaterialIcons-Regular'),
|
||||||
|
// url(/assets/MaterialIcons-Regular.woff2) format('woff2'),
|
||||||
|
// url(/assets/MaterialIcons-Regular.woff) format('woff'),
|
||||||
|
// url(/assets/MaterialIcons-Regular.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// .material-icons {
|
||||||
|
// font-family: 'Material Icons';
|
||||||
|
// font-weight: normal;
|
||||||
|
// font-style: normal;
|
||||||
|
// font-size: 24px; /* Preferred icon size */
|
||||||
|
// display: inline-block;
|
||||||
|
// line-height: 1;
|
||||||
|
// text-transform: none;
|
||||||
|
// letter-spacing: normal;
|
||||||
|
// word-wrap: normal;
|
||||||
|
// white-space: nowrap;
|
||||||
|
// direction: ltr;
|
||||||
|
|
||||||
|
// /* Support for all WebKit browsers. */
|
||||||
|
// -webkit-font-smoothing: antialiased;
|
||||||
|
// /* Support for Safari and Chrome. */
|
||||||
|
// text-rendering: optimizeLegibility;
|
||||||
|
|
||||||
|
// /* Support for Firefox. */
|
||||||
|
// -moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
// /* Support for IE. */
|
||||||
|
// font-feature-settings: 'liga';
|
||||||
|
// }
|
36
src/style/main.scss
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
$main-color: #448aff;
|
||||||
|
|
||||||
|
@import '~vue-material/dist/theme/engine'; // Import the theme engine
|
||||||
|
|
||||||
|
@mixin set-theme-light() {
|
||||||
|
@include md-register-theme(
|
||||||
|
'default',
|
||||||
|
(
|
||||||
|
primary: md-get-palette-color(blue, A200),
|
||||||
|
// The primary color of your application
|
||||||
|
|
||||||
|
accent: md-get-palette-color(red, A200),
|
||||||
|
// The accent or secondary color
|
||||||
|
|
||||||
|
theme: light// This can be dark or light
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin set-theme-dark() {
|
||||||
|
@include md-register-theme(
|
||||||
|
'default',
|
||||||
|
(
|
||||||
|
primary: md-get-palette-color(blue, A200),
|
||||||
|
// The primary color of your application
|
||||||
|
|
||||||
|
accent: md-get-palette-color(red, A200),
|
||||||
|
// The accent or secondary color
|
||||||
|
|
||||||
|
theme: dark// This can be dark or light
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@import '~vue-material/dist/theme/all'; // Apply the theme
|
1
src/svg/canary-white.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="200px" height="200.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M921.6 716.75904L415.46752 210.66752a136.25344 136.25344 0 0 0-96.54272-39.99744c-70.93248 0-128.53248 54.272-135.19872 123.43296L102.4 375.43936h86.12864C210.59584 506.39872 294.57408 616.09984 409.6 673.49504v179.84512h68.27008V700.34432a405.18656 405.18656 0 0 0 68.25984 13.70112v139.30496H614.4V716.75904h307.2zM448.93184 340.6336L620.2368 511.95904h-39.95648c-75.27424 0-136.54016-61.22496-136.54016-136.52992-0.01024-12.12416 2.12992-23.63392 5.19168-34.79552z m-198.26688-33.46432a68.32128 68.32128 0 0 1 68.25984-68.22912c18.19648 0 35.36896 7.09632 48.27136 19.99872l28.4672 28.4672a202.37312 202.37312 0 0 0-20.20352 88.03328c0 112.92672 91.86304 204.8 204.8 204.8h108.22656l68.27008 68.25984H592.00512c-188.20096 0-341.34016-153.1392-341.34016-341.32992z" /></svg>
|
After Width: | Height: | Size: 1.0 KiB |
1
src/svg/canary.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1582191167349" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3270" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M921.6 716.75904L415.46752 210.66752a136.25344 136.25344 0 0 0-96.54272-39.99744c-70.93248 0-128.53248 54.272-135.19872 123.43296L102.4 375.43936h86.12864C210.59584 506.39872 294.57408 616.09984 409.6 673.49504v179.84512h68.27008V700.34432a405.18656 405.18656 0 0 0 68.25984 13.70112v139.30496H614.4V716.75904h307.2zM448.93184 340.6336L620.2368 511.95904h-39.95648c-75.27424 0-136.54016-61.22496-136.54016-136.52992-0.01024-12.12416 2.12992-23.63392 5.19168-34.79552z m-198.26688-33.46432a68.32128 68.32128 0 0 1 68.25984-68.22912c18.19648 0 35.36896 7.09632 48.27136 19.99872l28.4672 28.4672a202.37312 202.37312 0 0 0-20.20352 88.03328c0 112.92672 91.86304 204.8 204.8 204.8h108.22656l68.27008 68.25984H592.00512c-188.20096 0-341.34016-153.1392-341.34016-341.32992z" p-id="3271" fill="#bbdefb"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/svg/file_copy.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z"/></svg>
|
After Width: | Height: | Size: 274 B |
19
src/utils/aes.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import CryptoJS from 'crypto-js'
|
||||||
|
|
||||||
|
// aes加密用户密码
|
||||||
|
export function encryptMainCode(code) {
|
||||||
|
let default_key = 'e08b44a351a3'
|
||||||
|
return CryptoJS.AES.encrypt(code, CryptoJS.enc.Utf8.parse(default_key), {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// aes解密用户密码
|
||||||
|
export function decryptMainCode(row_code) {
|
||||||
|
let default_key = 'e08b44a351a3'
|
||||||
|
return CryptoJS.AES.decrypt(row_code, CryptoJS.enc.Utf8.parse(default_key), {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString(CryptoJS.enc.Utf8);
|
||||||
|
}
|
15
src/utils/formatTime.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export function formatDateTime(inputTime) {
|
||||||
|
var date = new Date(inputTime);
|
||||||
|
var y = date.getFullYear();
|
||||||
|
var m = date.getMonth() + 1;
|
||||||
|
m = m < 10 ? "0" + m : m;
|
||||||
|
var d = date.getDate();
|
||||||
|
d = d < 10 ? "0" + d : d;
|
||||||
|
var h = date.getHours();
|
||||||
|
h = h < 10 ? "0" + h : h;
|
||||||
|
var minute = date.getMinutes();
|
||||||
|
var second = date.getSeconds();
|
||||||
|
minute = minute < 10 ? "0" + minute : minute;
|
||||||
|
second = second < 10 ? "0" + second : second;
|
||||||
|
return y + "-" + m + "-" + d + " " + h + ":" + minute + ":" + second;
|
||||||
|
}
|
7
src/utils/px2rem.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//px2rem
|
||||||
|
export function setHtmlFontSize() {
|
||||||
|
const htmlWidth = document.documentElement.clientWidth || document.body.clientWidth
|
||||||
|
const htmlDom = document.getElementsByTagName('html')[0]
|
||||||
|
if (htmlWidth >= 500) htmlDom.style.fontSize = 500 / 10 + 'px'
|
||||||
|
else htmlDom.style.fontSize = htmlWidth / 10 + 'px'
|
||||||
|
}
|
477
src/views/Account/Account.vue
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
<template>
|
||||||
|
<div class="account" ref="account">
|
||||||
|
<md-app md-waterfall md-mode="fixed">
|
||||||
|
<md-app-toolbar class="md-primary">
|
||||||
|
<div class="md-toolbar-section-start">
|
||||||
|
<span class="md-title page-title">曳光</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-toolbar-section-end">
|
||||||
|
<div class="sroll-top-area"></div>
|
||||||
|
<md-button class="md-icon-button" @click="refresh" v-if="Object.keys(this.user_info).length != 0">
|
||||||
|
<md-icon>refresh</md-icon>
|
||||||
|
</md-button>
|
||||||
|
</div>
|
||||||
|
</md-app-toolbar>
|
||||||
|
<md-app-content>
|
||||||
|
<div ref="list_placeholder" :style="`height:40px`"></div>
|
||||||
|
<md-progress-bar
|
||||||
|
v-if="loading_switch"
|
||||||
|
md-mode="indeterminate"
|
||||||
|
style="position: absolute; top: 56px; left: 0; width: 100%;"
|
||||||
|
></md-progress-bar>
|
||||||
|
<template v-if="Object.keys(this.user_info).length == 0">
|
||||||
|
<md-field style="margin-top: 30px;">
|
||||||
|
<label>教务账号</label>
|
||||||
|
<md-input
|
||||||
|
v-model="cid"
|
||||||
|
placeholder="请输入您的教务账号"
|
||||||
|
type="number"
|
||||||
|
maxlength="10"
|
||||||
|
@focus="focus_list_1 = 1;focusOrBlur()"
|
||||||
|
@blur="focus_list_1 = 0;focusOrBlur()"
|
||||||
|
></md-input>
|
||||||
|
</md-field>
|
||||||
|
<md-field style="margin-top: 30px;">
|
||||||
|
<label>教务密码</label>
|
||||||
|
<md-input
|
||||||
|
v-model="pwd"
|
||||||
|
placeholder="请输入您的教务密码"
|
||||||
|
@focus="focus_list_2 = 1;focusOrBlur()"
|
||||||
|
@blur="focus_list_2 = 0;focusOrBlur()"
|
||||||
|
></md-input>
|
||||||
|
</md-field>
|
||||||
|
<md-button class="md-raised md-primary expand login-submit" @click="login()" :disabled="loading_switch">登录</md-button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<md-list>
|
||||||
|
<md-subheader class="md-primary">用户信息</md-subheader>
|
||||||
|
<md-list-item>
|
||||||
|
<span class="md-list-item-text">学号:{{user_info.id}}</span>
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
<span class="md-list-item-text">姓名:{{user_info.name}}</span>
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
<span class="md-list-item-text">一卡通号:{{user_info.cid}}</span>
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
<span class="md-list-item-text">昵称:{{user_info.nick}}</span>
|
||||||
|
<md-button class="md-icon-button md-list-action" @click="nick_dialog_switch = true">
|
||||||
|
<md-icon>edit</md-icon>
|
||||||
|
</md-button>
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
<span class="md-list-item-text">消息:{{user_info.msg.length}}条</span>
|
||||||
|
<md-button class="md-icon-button md-list-action">
|
||||||
|
<span>查看</span>
|
||||||
|
</md-button>
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
<span class="md-list-item-text">已发布:{{user_info.created.length}}条</span>
|
||||||
|
<md-button class="md-icon-button md-list-action">
|
||||||
|
<span>查看</span>
|
||||||
|
</md-button>
|
||||||
|
</md-list-item>
|
||||||
|
<md-subheader class="md-primary">应用设置</md-subheader>
|
||||||
|
<md-list-item>
|
||||||
|
<md-icon>brightness_6</md-icon>
|
||||||
|
<span class="md-list-item-text">黑暗模式</span>
|
||||||
|
<md-switch v-model="is_dark_mode" class="md-primary"></md-switch>
|
||||||
|
</md-list-item>
|
||||||
|
<md-list-item>
|
||||||
|
<md-icon>code</md-icon>
|
||||||
|
<span class="md-list-item-text">VConsole</span>
|
||||||
|
<md-switch v-model="open_vconsole" class="md-primary"></md-switch>
|
||||||
|
</md-list-item>
|
||||||
|
<md-button
|
||||||
|
class=" md-raised md-primary expand"
|
||||||
|
@click="logout_confirm_switch = true"
|
||||||
|
>退出登录</md-button>
|
||||||
|
</md-list>
|
||||||
|
</template>
|
||||||
|
<md-dialog-confirm
|
||||||
|
:md-active.sync="logout_confirm_switch"
|
||||||
|
md-title="警告"
|
||||||
|
md-content="您将退出登录,该操作将清空本地信息"
|
||||||
|
md-confirm-text="继续"
|
||||||
|
md-cancel-text="取消"
|
||||||
|
@md-confirm="logout"
|
||||||
|
:md-click-outside-to-close="false"
|
||||||
|
/>
|
||||||
|
<md-dialog-prompt
|
||||||
|
:md-active.sync="nick_dialog_switch"
|
||||||
|
v-model="nick"
|
||||||
|
md-title="修改昵称"
|
||||||
|
md-input-maxlength="10"
|
||||||
|
md-input-placeholder="新的昵称..."
|
||||||
|
md-confirm-text="提交"
|
||||||
|
md-cancel-text="取消"
|
||||||
|
@md-confirm="modifyNick"
|
||||||
|
/>
|
||||||
|
<md-snackbar
|
||||||
|
md-position="center"
|
||||||
|
:md-active.sync="show_snackbar"
|
||||||
|
md-persistent
|
||||||
|
:md-duration="1500"
|
||||||
|
>
|
||||||
|
<span>{{ snakebar_msg }}</span>
|
||||||
|
</md-snackbar>
|
||||||
|
|
||||||
|
<div :style="`height:60px`"></div>
|
||||||
|
</md-app-content>
|
||||||
|
</md-app>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import { mapState, mapActions } from "vuex";
|
||||||
|
import { setHtmlFontSize } from "@/utils/px2rem.js";
|
||||||
|
import { api } from "@/axios/fetch.js";
|
||||||
|
import { encryptMainCode, decryptMainCode } from "@/utils/aes.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Account",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 显示高度,控制md-app的最小高度,防止抽屉高度塌陷
|
||||||
|
clientHeight: "",
|
||||||
|
// snackbar控制
|
||||||
|
show_snackbar: false,
|
||||||
|
snakebar_msg: "",
|
||||||
|
// 登录cid
|
||||||
|
cid: "",
|
||||||
|
// 登录pwd
|
||||||
|
pwd: "",
|
||||||
|
// 加载控制
|
||||||
|
loading_switch: false,
|
||||||
|
// 黑暗模式
|
||||||
|
is_dark_mode: false,
|
||||||
|
// vconsole
|
||||||
|
open_vconsole: false,
|
||||||
|
// 初始化完成状态
|
||||||
|
has_init: false,
|
||||||
|
// 退出登录confirm
|
||||||
|
logout_confirm_switch: false,
|
||||||
|
// 监听输入事件
|
||||||
|
focus_list_1: 0,
|
||||||
|
focus_list_2: 0,
|
||||||
|
// 昵称输入弹窗
|
||||||
|
nick_dialog_switch: false,
|
||||||
|
// 新输入的昵称
|
||||||
|
nick: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["user_info", "settings"])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(["setUserInfo", "setSettings", "setBarState"]),
|
||||||
|
// 修改md-app的最小高度
|
||||||
|
changeFixed(clientHeight) {
|
||||||
|
//动态修改样式
|
||||||
|
this.$refs.account.children[0].style.minHeight = clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.style.maxHeight =
|
||||||
|
clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.style.minHeight =
|
||||||
|
clientHeight - 32 + "px";
|
||||||
|
window.document.documentElement.setAttribute(
|
||||||
|
"data-theme",
|
||||||
|
this.settings.is_dark_mode ? "dark" : "light"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
init() {
|
||||||
|
// 刷新vuex
|
||||||
|
this.$store.replaceState(
|
||||||
|
Object.assign(
|
||||||
|
this.$store.state,
|
||||||
|
JSON.parse(localStorage.getItem("storeState"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// 底部状态栏状态设置
|
||||||
|
this.setBarState([true, this])
|
||||||
|
// 初始化本页信息
|
||||||
|
this.open_vconsole = this.settings.open_vconsole;
|
||||||
|
this.is_dark_mode = this.settings.is_dark_mode;
|
||||||
|
// 设置flag
|
||||||
|
setTimeout(
|
||||||
|
function() {
|
||||||
|
this.has_init = true;
|
||||||
|
console.log("本页信息覆写完成");
|
||||||
|
}.bind(this),
|
||||||
|
10
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 管理员登录
|
||||||
|
login(is_refresh = false) {
|
||||||
|
// 格式校验
|
||||||
|
if (!/\d+/.test(this.cid)) {
|
||||||
|
console.log("数据格式校验失败");
|
||||||
|
this.message("请输入正确的教务账号");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(this.pwd = this.pwd.trim())) {
|
||||||
|
console.log("数据格式校验失败");
|
||||||
|
this.message("请输入的教务密码");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loading_switch = true;
|
||||||
|
let data = {
|
||||||
|
cid: this.cid,
|
||||||
|
pwd: this.pwd
|
||||||
|
};
|
||||||
|
console.log(`上传信息准备完成`);
|
||||||
|
console.log(data);
|
||||||
|
api
|
||||||
|
.post("/login", data)
|
||||||
|
.then(res => {
|
||||||
|
let user_info = res.data.user_info;
|
||||||
|
user_info.pwd = encryptMainCode(this.pwd);
|
||||||
|
this.setUserInfo([user_info, this]);
|
||||||
|
console.log("登录成功,用户信息覆写完成");
|
||||||
|
let msg = is_refresh ? "刷新成功" : "登录成功";
|
||||||
|
this.message(msg);
|
||||||
|
this.loading_switch = false;
|
||||||
|
this.cid = "";
|
||||||
|
this.pwd = "";
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
this.loading_switch = false;
|
||||||
|
if (err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`);
|
||||||
|
} else {
|
||||||
|
this.message("网络错误,请稍候重试");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 刷新用户信息
|
||||||
|
refresh() {
|
||||||
|
if (Object.keys(this.user_info).length == 0) return;
|
||||||
|
this.cid = this.user_info.cid;
|
||||||
|
this.pwd = decryptMainCode(this.user_info.pwd);
|
||||||
|
this.login(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
//覆写个性化设置
|
||||||
|
resetSettings() {
|
||||||
|
let settings = {
|
||||||
|
open_vconsole: this.open_vconsole,
|
||||||
|
is_dark_mode: this.is_dark_mode
|
||||||
|
};
|
||||||
|
this.setSettings([settings, this]);
|
||||||
|
console.log("个性化设置覆写完成");
|
||||||
|
// 设置黑暗模式
|
||||||
|
window.document.documentElement.setAttribute(
|
||||||
|
"data-theme",
|
||||||
|
this.settings.is_dark_mode ? "dark" : "light"
|
||||||
|
);
|
||||||
|
// 设置vconsole
|
||||||
|
this.toggleVcon();
|
||||||
|
if(this.has_init)
|
||||||
|
this.message("设置成功");
|
||||||
|
},
|
||||||
|
// 调用snackBar
|
||||||
|
message(msg) {
|
||||||
|
this.snakebar_msg = msg;
|
||||||
|
this.show_snackbar = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 判断是否有class
|
||||||
|
hasClass(obj, cls) {
|
||||||
|
return obj.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
|
||||||
|
},
|
||||||
|
// 增加class
|
||||||
|
addClass(obj, cls) {
|
||||||
|
if (!this.hasClass(obj, cls)) obj.className += " " + cls;
|
||||||
|
},
|
||||||
|
// 移除class
|
||||||
|
removeClass(obj, cls) {
|
||||||
|
if (this.hasClass(obj, cls)) {
|
||||||
|
var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
|
||||||
|
obj.className = obj.className.replace(reg, " ");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 改变class
|
||||||
|
toggleVcon() {
|
||||||
|
let vcon_dom = document.getElementById("__vconsole");
|
||||||
|
let class_name = "vconsole-show";
|
||||||
|
if (this.hasClass(vcon_dom, class_name)) {
|
||||||
|
// 当前显示
|
||||||
|
if (!this.settings.open_vconsole) {
|
||||||
|
// 设置不显示
|
||||||
|
this.removeClass(vcon_dom, class_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 当前不显示
|
||||||
|
if (this.settings.open_vconsole) {
|
||||||
|
// 设置显示
|
||||||
|
this.addClass(vcon_dom, class_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 退出登录
|
||||||
|
logout() {
|
||||||
|
this.setUserInfo([{}, this]);
|
||||||
|
this.cid = "";
|
||||||
|
this.pwd = "";
|
||||||
|
console.log("用户信息覆写完成");
|
||||||
|
this.message("本地信息清空完成");
|
||||||
|
},
|
||||||
|
|
||||||
|
// 监听聚焦和脱焦事件控制bottomBar的显示和隐藏
|
||||||
|
focusOrBlur() {
|
||||||
|
let focus_list = [
|
||||||
|
this.focus_list_1,
|
||||||
|
this.focus_list_2,
|
||||||
|
this.focus_list_3,
|
||||||
|
this.focus_list_4
|
||||||
|
];
|
||||||
|
if (focus_list.indexOf(1) != -1) {
|
||||||
|
this.setBarState([false, this]);
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
let focus_list = [
|
||||||
|
this.focus_list_1,
|
||||||
|
this.focus_list_2,
|
||||||
|
this.focus_list_3,
|
||||||
|
this.focus_list_4
|
||||||
|
];
|
||||||
|
if (focus_list.indexOf(1) == -1) {
|
||||||
|
this.setBarState([true, this]);
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改昵称
|
||||||
|
modifyNick() {
|
||||||
|
this.nick_dialog_switch = false
|
||||||
|
this.loading_switch = true
|
||||||
|
let data = {
|
||||||
|
openid: this.user_info.openid,
|
||||||
|
nick: this.nick
|
||||||
|
}
|
||||||
|
api
|
||||||
|
.put("/nick", data)
|
||||||
|
.then(res => {
|
||||||
|
this.loading_switch = false;
|
||||||
|
let user_info = this.user_info
|
||||||
|
user_info.nick = this.nick
|
||||||
|
this.setUserInfo([user_info, this]);
|
||||||
|
console.log("用户信息覆写成功");
|
||||||
|
this.message('修改成功')
|
||||||
|
this.nick = ""
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
this.loading_switch = false;
|
||||||
|
if (err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`);
|
||||||
|
} else {
|
||||||
|
this.message("网络错误,请稍候重试");
|
||||||
|
}
|
||||||
|
this.nick = ""
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取浏览器可视区域高度
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
//document.body.clientWidth;
|
||||||
|
window.onresize = function temp() {
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
setHtmlFontSize();
|
||||||
|
}.bind(this);
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.addEventListener(
|
||||||
|
"scroll",
|
||||||
|
this.scroll
|
||||||
|
);
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 如果 `clientHeight` 发生改变,这个函数就会运行
|
||||||
|
clientHeight: function() {
|
||||||
|
this.changeFixed(this.clientHeight);
|
||||||
|
},
|
||||||
|
// 如果 `is_dark_mode` 发生改变,就会执行设置函数
|
||||||
|
is_dark_mode: function() {
|
||||||
|
this.resetSettings();
|
||||||
|
},
|
||||||
|
// 如果 `open_vconsole` 发生改变,就会执行设置函数
|
||||||
|
open_vconsole: function() {
|
||||||
|
this.resetSettings();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {},
|
||||||
|
components: {}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss" type="text/scss">
|
||||||
|
@import "../../style/main";
|
||||||
|
.account {
|
||||||
|
width: 100%;
|
||||||
|
// max-width: 500px;
|
||||||
|
min-height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
// margin: 0 auto;
|
||||||
|
.expand {
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-height: 0.8rem !important;
|
||||||
|
margin: 0.5rem 16px !important;
|
||||||
|
}
|
||||||
|
.login-submit {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0.5rem 0 !important;
|
||||||
|
}
|
||||||
|
.md-toolbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.md-toolbar-row {
|
||||||
|
order: 12;
|
||||||
|
// margin-bottom: .3rem !important;
|
||||||
|
}
|
||||||
|
.md-toolbar-section-start,
|
||||||
|
.md-toolbar-section-end,
|
||||||
|
.md-toolbar-row {
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
.md-toolbar-row {
|
||||||
|
margin-top: -10px;
|
||||||
|
}
|
||||||
|
.md-speed-dial.md-bottom-right {
|
||||||
|
position: fixed !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Demo purposes only
|
||||||
|
.md-drawer {
|
||||||
|
width: 240px;
|
||||||
|
max-width: calc(100vw - 125px);
|
||||||
|
}
|
||||||
|
.md-app-scroller > div {
|
||||||
|
overflow-y: scroll !important;
|
||||||
|
}
|
||||||
|
.face {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.page-title {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
line-height: 56px;
|
||||||
|
}
|
||||||
|
.sroll-top-area {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
.md-bottom-bar.md-type-fixed .md-bottom-bar-item {
|
||||||
|
max-width: 1000px !important;
|
||||||
|
}
|
||||||
|
</style>
|
410
src/views/Create/Create.vue
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
<template>
|
||||||
|
<div class="create" ref="create">
|
||||||
|
<md-app md-waterfall md-mode="fixed">
|
||||||
|
<md-app-toolbar class="md-primary">
|
||||||
|
<div class="md-toolbar-section-start">
|
||||||
|
<span class="md-title page-title">创建失物招领</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-toolbar-section-end">
|
||||||
|
<div class="sroll-top-area"></div>
|
||||||
|
</div>
|
||||||
|
</md-app-toolbar>
|
||||||
|
<md-app-content>
|
||||||
|
<div ref="list_placeholder" :style="`height:56px`"></div>
|
||||||
|
<md-progress-bar
|
||||||
|
v-if="loading_switch"
|
||||||
|
md-mode="indeterminate"
|
||||||
|
style="position: absolute; top: 56px; left: 0; width: 100%;"
|
||||||
|
></md-progress-bar>
|
||||||
|
|
||||||
|
<md-content>
|
||||||
|
<md-radio class="md-primary" v-model="type" value="lost">丢了东西</md-radio>
|
||||||
|
<md-radio class="md-primary" v-model="type" value="found">捡到东西</md-radio>
|
||||||
|
</md-content>
|
||||||
|
<md-field style="margin-top: -10px;">
|
||||||
|
<label>标题*</label>
|
||||||
|
<md-input
|
||||||
|
v-model="title"
|
||||||
|
maxlength="15"
|
||||||
|
id="title"
|
||||||
|
@focus="focus_list_1 = 1;focusOrBlur()"
|
||||||
|
@blur="focus_list_1 = 0;focusOrBlur()"
|
||||||
|
></md-input>
|
||||||
|
<span class="md-helper-text">譬如:水杯、手机等易于搜索的~</span>
|
||||||
|
</md-field>
|
||||||
|
<md-field style="margin-top:40px;">
|
||||||
|
<label>描述</label>
|
||||||
|
<md-textarea
|
||||||
|
v-model="content"
|
||||||
|
maxlength="100"
|
||||||
|
@focus="focus_list_2 = 1;focusOrBlur()"
|
||||||
|
@blur="focus_list_2 = 0;focusOrBlur()"
|
||||||
|
></md-textarea>
|
||||||
|
<span class="md-helper-text">描述一下它的特征之类的</span>
|
||||||
|
</md-field>
|
||||||
|
<md-field style="margin-top:40px;">
|
||||||
|
<label for="total_addr">地区*</label>
|
||||||
|
<md-select v-model="total_addr" name="total_addr" id="total_addr">
|
||||||
|
<md-option value="长理东区">长理东区</md-option>
|
||||||
|
<md-option value="长理南区">长理南区</md-option>
|
||||||
|
<md-option value="长理西区">长理西区</md-option>
|
||||||
|
</md-select>
|
||||||
|
</md-field>
|
||||||
|
<md-field style="margin-top: -10px;">
|
||||||
|
<label>具体位置*</label>
|
||||||
|
<md-input
|
||||||
|
v-model="detail_addr"
|
||||||
|
maxlength="30"
|
||||||
|
@focus="focus_list_3 = 1;focusOrBlur()"
|
||||||
|
@blur="focus_list_3 = 0;focusOrBlur()"
|
||||||
|
></md-input>
|
||||||
|
<span class="md-helper-text">譬如:南研楼1201阶梯教室第四排~</span>
|
||||||
|
</md-field>
|
||||||
|
<md-field>
|
||||||
|
<label>联系方式</label>
|
||||||
|
<md-input
|
||||||
|
v-model="contact"
|
||||||
|
maxlength="20"
|
||||||
|
@focus="focus_list_4 = 1;focusOrBlur()"
|
||||||
|
@blur="focus_list_4 = 0;focusOrBlur()"
|
||||||
|
></md-input>
|
||||||
|
<span class="md-helper-text">譬如:手机号,微信号,qq号(非必填项</span>
|
||||||
|
</md-field>
|
||||||
|
<md-field style="margin-top:40px;">
|
||||||
|
<label>图片上传</label>
|
||||||
|
<md-file v-model="upload_file" accept="image/*" @md-change="processFile"/>
|
||||||
|
</md-field>
|
||||||
|
<md-button
|
||||||
|
class="md-dense md-raised md-primary expand"
|
||||||
|
@click="judge()"
|
||||||
|
:disable="!loading_switch"
|
||||||
|
>确认提交</md-button>
|
||||||
|
<md-dialog-confirm
|
||||||
|
:md-active.sync="submit_confirm_switch"
|
||||||
|
md-title="提示"
|
||||||
|
md-content="该信息即将提交审核,是否继续"
|
||||||
|
md-confirm-text="继续"
|
||||||
|
md-cancel-text="取消"
|
||||||
|
@md-confirm="uploadPhoto"
|
||||||
|
:md-click-outside-to-close="false"
|
||||||
|
/>
|
||||||
|
<md-dialog-alert
|
||||||
|
:md-active.sync="error_alert_switch"
|
||||||
|
md-title="警告"
|
||||||
|
md-content="请检查您所填写的内容</br>除了联系方式以及图片皆为<strong>必填项</strong></br>还请注意<strong>输入长度</strong>"
|
||||||
|
md-confirm-text="我知道了"/>
|
||||||
|
|
||||||
|
<md-snackbar
|
||||||
|
md-position="center"
|
||||||
|
:md-active.sync="show_snackbar"
|
||||||
|
md-persistent
|
||||||
|
:md-duration="1500"
|
||||||
|
>
|
||||||
|
<span>{{ snakebar_msg }}</span>
|
||||||
|
</md-snackbar>
|
||||||
|
<div :style="`height:86px`"></div>
|
||||||
|
</md-app-content>
|
||||||
|
</md-app>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import { mapState, mapActions } from "vuex";
|
||||||
|
import { setHtmlFontSize } from "@/utils/px2rem.js";
|
||||||
|
import { api } from "@/axios/fetch.js";
|
||||||
|
import "lrz";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Create",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 显示高度,控制md-app的最小高度,防止抽屉高度塌陷
|
||||||
|
clientHeight: "",
|
||||||
|
// snackbar控制
|
||||||
|
show_snackbar: false,
|
||||||
|
snakebar_msg: "",
|
||||||
|
// 类型
|
||||||
|
type: "lost",
|
||||||
|
// 标题
|
||||||
|
title: "",
|
||||||
|
// 内容
|
||||||
|
content: "",
|
||||||
|
// 地区
|
||||||
|
total_addr: "长理东区",
|
||||||
|
// 详细地址
|
||||||
|
detail_addr: "",
|
||||||
|
// 联系方式
|
||||||
|
contact: "",
|
||||||
|
// 图片
|
||||||
|
upload_file: null,
|
||||||
|
// 压缩后图片
|
||||||
|
lrz_file: null,
|
||||||
|
// 加载控制
|
||||||
|
loading_switch: false,
|
||||||
|
// 监听输入事件
|
||||||
|
focus_list_1: 0,
|
||||||
|
focus_list_2: 0,
|
||||||
|
focus_list_3: 0,
|
||||||
|
focus_list_4: 0,
|
||||||
|
// 确认提交框
|
||||||
|
submit_confirm_switch: false,
|
||||||
|
// 错误提醒框
|
||||||
|
error_alert_switch: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["user_info", "settings"])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(["setUserInfo", "setSettings", "setBarState"]),
|
||||||
|
|
||||||
|
// 修改md-app的最小高度
|
||||||
|
changeFixed(clientHeight) {
|
||||||
|
//动态修改样式
|
||||||
|
this.$refs.create.children[0].style.minHeight = clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.style.maxHeight =
|
||||||
|
clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.style.minHeight =
|
||||||
|
clientHeight - 32 + "px";
|
||||||
|
window.document.documentElement.setAttribute(
|
||||||
|
"data-theme",
|
||||||
|
this.settings.is_dark_mode ? "dark" : "light"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
init() {
|
||||||
|
// 刷新vuex
|
||||||
|
this.$store.replaceState(
|
||||||
|
Object.assign(
|
||||||
|
this.$store.state,
|
||||||
|
JSON.parse(localStorage.getItem("storeState"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// 底部状态栏状态设置
|
||||||
|
this.setBarState([true, this])
|
||||||
|
},
|
||||||
|
|
||||||
|
// 调用snackBar
|
||||||
|
message(msg) {
|
||||||
|
this.snakebar_msg = msg;
|
||||||
|
this.show_snackbar = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 监听聚焦和脱焦事件控制bottomBar的显示和隐藏
|
||||||
|
focusOrBlur() {
|
||||||
|
let focus_list = [this.focus_list_1, this.focus_list_2, this.focus_list_3, this.focus_list_4]
|
||||||
|
if (focus_list.indexOf(1) != -1) {
|
||||||
|
this.setBarState([false, this]);
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
let focus_list = [this.focus_list_1, this.focus_list_2, this.focus_list_3, this.focus_list_4]
|
||||||
|
if (focus_list.indexOf(1) == -1) {
|
||||||
|
this.setBarState([true, this]);
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户点击上传校验输入信息
|
||||||
|
judge() {
|
||||||
|
if(Object.keys(this.user_info).length == 0) {
|
||||||
|
this.message('请先登录')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let flag = true
|
||||||
|
this.title = this.title.trim()
|
||||||
|
if(!this.title || this.title.length > 15) flag = false
|
||||||
|
this.content = this.content.trim()
|
||||||
|
if(!this.content || this.content.length > 100) flag = false
|
||||||
|
this.detail_addr = this.detail_addr.trim()
|
||||||
|
if(!this.detail_addr || this.detail_addr.length > 30) flag = false
|
||||||
|
this.contact = this.contact.trim()
|
||||||
|
flag ? this.submit_confirm_switch = true : this.error_alert_switch = true
|
||||||
|
},
|
||||||
|
|
||||||
|
// 准备图片上传
|
||||||
|
uploadPhoto() {
|
||||||
|
this.loading_switch = true;
|
||||||
|
if(!this.lrz_file) this.uploadData('default.jpg')
|
||||||
|
let param = new FormData();
|
||||||
|
param.append('photo', this.lrz_file);
|
||||||
|
api.put('/upload', param, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
this.uploadData(res.data.file_name)
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
this.loading_switch = false;
|
||||||
|
if(err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`)
|
||||||
|
} else {
|
||||||
|
this.message('网络错误,请稍候重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传信息
|
||||||
|
uploadData(file_name) {
|
||||||
|
console.log('文件上传成功,文件名:', file_name)
|
||||||
|
// 组织信息
|
||||||
|
let data = {
|
||||||
|
title: this.title,
|
||||||
|
content: this.content,
|
||||||
|
create_time: new Date().getTime(),
|
||||||
|
img_url: file_name,
|
||||||
|
total_addr: this.total_addr,
|
||||||
|
detail_addr: this.detail_addr,
|
||||||
|
contact: this.contact,
|
||||||
|
type: this.type,
|
||||||
|
user_info: {
|
||||||
|
openid: this.user_info.openid,
|
||||||
|
nick: this.user_info.nick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api.post('/add', data).then(res => {
|
||||||
|
console.log('上传成功')
|
||||||
|
this.loading_switch = false;
|
||||||
|
this.message('上传成功,请等待审核')
|
||||||
|
this.initData()
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
this.loading_switch = false;
|
||||||
|
if(err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`)
|
||||||
|
} else {
|
||||||
|
this.message('网络错误,请稍候重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传成功初始化本页信息
|
||||||
|
initData() {
|
||||||
|
this.type = "lost";
|
||||||
|
this.title = '';
|
||||||
|
this.content = '';
|
||||||
|
this.total_addr = "长理东区";
|
||||||
|
this.detail_addr = ""
|
||||||
|
this.contact = ""
|
||||||
|
this.upload_file = null
|
||||||
|
this.lrz_file = null
|
||||||
|
console.log('创建信息初始化完成')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理图片文件
|
||||||
|
processFile: async function(e) {
|
||||||
|
let file = e[0]
|
||||||
|
if (file) {
|
||||||
|
let name = file.name
|
||||||
|
console.log('文件压缩开始')
|
||||||
|
file = await lrz(file);
|
||||||
|
file = file.file;
|
||||||
|
file = new File([file], name);
|
||||||
|
this.lrz_file = file;
|
||||||
|
console.log('文件压缩完成', this.lrz_file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取浏览器可视区域高度
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
//document.body.clientWidth;
|
||||||
|
window.onresize = function temp() {
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
setHtmlFontSize();
|
||||||
|
}.bind(this);
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.addEventListener(
|
||||||
|
"scroll",
|
||||||
|
this.scroll
|
||||||
|
);
|
||||||
|
// document.getElementById("title")
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 如果 `clientHeight` 发生改变,这个函数就会运行
|
||||||
|
clientHeight: function() {
|
||||||
|
this.changeFixed(this.clientHeight);
|
||||||
|
},
|
||||||
|
// upload_file: async function() {
|
||||||
|
// if(typeof(this.upload_file) == 'object') return
|
||||||
|
// console.log(this.upload_file)
|
||||||
|
// let file = this.upload_file
|
||||||
|
// if (file) {
|
||||||
|
// let name = file.name
|
||||||
|
// console.log('文件压缩开始')
|
||||||
|
// file = await lrz(file);
|
||||||
|
// file = file.file;
|
||||||
|
// file = new File([file], name);
|
||||||
|
// this.lrz_file = file;
|
||||||
|
// console.log('文件压缩完成', this.lrz_file)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
beforeDestroy() {},
|
||||||
|
components: {}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss" type="text/scss">
|
||||||
|
@import "../../style/main";
|
||||||
|
.create {
|
||||||
|
width: 100%;
|
||||||
|
// max-width: 500px;
|
||||||
|
min-height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
// margin: 0 auto;
|
||||||
|
.expand {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 !important;
|
||||||
|
min-height: 0.8rem !important;
|
||||||
|
margin-top: 0.5rem !important;
|
||||||
|
}
|
||||||
|
.md-toolbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.md-toolbar-row {
|
||||||
|
order: 12;
|
||||||
|
// margin-bottom: .3rem !important;
|
||||||
|
}
|
||||||
|
.md-toolbar-section-start,
|
||||||
|
.md-toolbar-section-end,
|
||||||
|
.md-toolbar-row {
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
.md-toolbar-row {
|
||||||
|
margin-top: -10px;
|
||||||
|
}
|
||||||
|
.md-speed-dial.md-bottom-right {
|
||||||
|
position: fixed !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Demo purposes only
|
||||||
|
.md-drawer {
|
||||||
|
width: 240px;
|
||||||
|
max-width: calc(100vw - 125px);
|
||||||
|
}
|
||||||
|
.md-app-scroller > div {
|
||||||
|
overflow-y: scroll !important;
|
||||||
|
}
|
||||||
|
.face {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.page-title {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
line-height: 56px;
|
||||||
|
}
|
||||||
|
.sroll-top-area {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
.md-bottom-bar.md-type-fixed .md-bottom-bar-item {
|
||||||
|
max-width: 1000px !important;
|
||||||
|
}
|
||||||
|
</style>
|
483
src/views/Detail/Detail.vue
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
<template>
|
||||||
|
<div class="detail" ref="detail">
|
||||||
|
<md-app md-waterfall md-mode="fixed">
|
||||||
|
<md-app-toolbar class="md-primary">
|
||||||
|
<div class="md-toolbar-section-start">
|
||||||
|
<md-button class="md-icon-button" @click="back">
|
||||||
|
<md-icon>arrow_back</md-icon>
|
||||||
|
</md-button>
|
||||||
|
<span class="md-title page-title">曳光 - 详情</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-toolbar-section-end">
|
||||||
|
<md-button
|
||||||
|
class="md-icon-button"
|
||||||
|
@click="comment_dialog_switch = true; is_comment = true"
|
||||||
|
v-if="Object.keys(user_info).length != 0 && content && content.close == false"
|
||||||
|
>
|
||||||
|
<md-icon>rate_review</md-icon>
|
||||||
|
</md-button>
|
||||||
|
<md-button
|
||||||
|
class="md-icon-button"
|
||||||
|
v-if="Object.keys(user_info).length != 0 && content && user_info.openid == content.user_info.openid && content.close == false"
|
||||||
|
@click="delete_confirm_switch = true"
|
||||||
|
>
|
||||||
|
<md-icon>delete</md-icon>
|
||||||
|
</md-button>
|
||||||
|
</div>
|
||||||
|
</md-app-toolbar>
|
||||||
|
<md-app-content>
|
||||||
|
<v-touch
|
||||||
|
@swiperight="back"
|
||||||
|
:swipe-options="{ direction: 'horizontal' }"
|
||||||
|
>
|
||||||
|
<div ref="list_placeholder" :style="`height:56px`"></div>
|
||||||
|
<md-progress-bar
|
||||||
|
v-if="loading_switch"
|
||||||
|
md-mode="indeterminate"
|
||||||
|
style="position: absolute; top: 56px; left: 0; width: 100%;"
|
||||||
|
></md-progress-bar>
|
||||||
|
<icon class="loading" name="canary" v-if="!content"></icon>
|
||||||
|
<md-card class="md-card-example" v-else>
|
||||||
|
<md-card-area md-inset>
|
||||||
|
<md-card-media>
|
||||||
|
<img :src="`https://yg.canary.moe/photo/${content.img_url}`" />
|
||||||
|
</md-card-media>
|
||||||
|
|
||||||
|
<md-card-header>
|
||||||
|
<h2 class="md-title" style="margin-bottom: .3rem;">{{content.title}}</h2>
|
||||||
|
<div class="md-subhead">
|
||||||
|
<md-icon>access_time</md-icon>
|
||||||
|
<span>{{formatDateTime(content.create_time)}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-subhead">
|
||||||
|
<md-icon>location_on</md-icon>
|
||||||
|
<span>{{content.total_addr}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-subhead">
|
||||||
|
<md-icon>gps_fixed</md-icon>
|
||||||
|
<span>{{content.detail_addr}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-subhead" v-if="content.contact">
|
||||||
|
<md-icon>attach_file</md-icon>
|
||||||
|
<span>{{content.contact}}</span>
|
||||||
|
</div>
|
||||||
|
</md-card-header>
|
||||||
|
<md-card-content>{{content.content}}</md-card-content>
|
||||||
|
</md-card-area>
|
||||||
|
</md-card>
|
||||||
|
|
||||||
|
<md-list
|
||||||
|
class="md-double-line md-dense"
|
||||||
|
style="margin-top: .3rem;"
|
||||||
|
v-if="content && Object.keys(content.comment).length != 0"
|
||||||
|
>
|
||||||
|
<md-subheader class="md-primary">评论区</md-subheader>
|
||||||
|
<div v-for="(comment, index0) in content.comment" :key="index0">
|
||||||
|
<md-list-item>
|
||||||
|
<div class="md-list-item-text">
|
||||||
|
<span>{{comment.user_info.nick}}</span>
|
||||||
|
<p>{{comment.content}}</p>
|
||||||
|
<p>{{formatDateTime(comment.create_time)}}</p>
|
||||||
|
</div>
|
||||||
|
<md-button
|
||||||
|
class="md-icon-button md-list-action"
|
||||||
|
@click="targetReply(index0, comment.user_info.nick)"
|
||||||
|
v-if="Object.keys(user_info).length != 0 && content.close == false"
|
||||||
|
>
|
||||||
|
<md-icon>rate_review</md-icon>
|
||||||
|
</md-button>
|
||||||
|
</md-list-item>
|
||||||
|
<div v-for="(reply, index1) in comment.reply" :key="index1">
|
||||||
|
<md-list-item>
|
||||||
|
<md-icon class="md-primary">keyboard_arrow_right</md-icon>
|
||||||
|
<div class="md-list-item-text">
|
||||||
|
<span>{{reply.user_info.nick}}</span>
|
||||||
|
<p>{{reply.content}}</p>
|
||||||
|
<span>{{formatDateTime(reply.create_time)}}</span>
|
||||||
|
</div>
|
||||||
|
<md-button
|
||||||
|
class="md-icon-button md-list-action"
|
||||||
|
@click="targetReply(index0, reply.user_info.nick)"
|
||||||
|
v-if="Object.keys(user_info).length != 0 && content.close == false"
|
||||||
|
>
|
||||||
|
<md-icon>rate_review</md-icon>
|
||||||
|
</md-button>
|
||||||
|
</md-list-item>
|
||||||
|
</div>
|
||||||
|
<md-divider style="margin-top: .3rem;margin-bottom: .3rem;"></md-divider>
|
||||||
|
</div>
|
||||||
|
</md-list>
|
||||||
|
|
||||||
|
<md-dialog-confirm
|
||||||
|
:md-active.sync="delete_confirm_switch"
|
||||||
|
md-title="警告"
|
||||||
|
md-content="您将关闭该条记录</br>该操作不可复原,是否继续"
|
||||||
|
md-confirm-text="继续"
|
||||||
|
md-cancel-text="取消"
|
||||||
|
:md-click-outside-to-close="false"
|
||||||
|
@md-confirm="closeLaf"
|
||||||
|
/>
|
||||||
|
<md-dialog-prompt
|
||||||
|
:md-active.sync="comment_dialog_switch"
|
||||||
|
v-model="comment"
|
||||||
|
:md-title="is_comment ? '评论': '回复'"
|
||||||
|
md-input-maxlength="30"
|
||||||
|
:md-input-placeholder="`${is_comment ? '评论': '回复'}的内容...`"
|
||||||
|
md-confirm-text="提交"
|
||||||
|
md-cancel-text="取消"
|
||||||
|
@md-confirm="commentSubmit"
|
||||||
|
@md-cancel="commentCancel"
|
||||||
|
/>
|
||||||
|
<md-snackbar
|
||||||
|
md-position="center"
|
||||||
|
:md-active.sync="show_snackbar"
|
||||||
|
md-persistent
|
||||||
|
:md-duration="1500"
|
||||||
|
>
|
||||||
|
<span>{{ snakebar_msg }}</span>
|
||||||
|
</md-snackbar>
|
||||||
|
<div style="height: 40px;"></div>
|
||||||
|
</v-touch>
|
||||||
|
</md-app-content>
|
||||||
|
</md-app>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import { mapState, mapActions } from "vuex";
|
||||||
|
import { setHtmlFontSize } from "@/utils/px2rem.js";
|
||||||
|
import { api } from "@/axios/fetch.js";
|
||||||
|
import { encryptMainCode, decryptMainCode } from "@/utils/aes.js";
|
||||||
|
import { formatDateTime } from "@/utils/formatTime.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Detail",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 显示高度,控制md-app的最小高度,防止抽屉高度塌陷
|
||||||
|
clientHeight: "",
|
||||||
|
// snackbar控制
|
||||||
|
show_snackbar: false,
|
||||||
|
snakebar_msg: "",
|
||||||
|
// 页面内容
|
||||||
|
content: null,
|
||||||
|
// 加载控制
|
||||||
|
loading_switch: false,
|
||||||
|
// 删除确认弹窗控制
|
||||||
|
delete_confirm_switch: false,
|
||||||
|
// 提交评论
|
||||||
|
comment_dialog_switch: false,
|
||||||
|
comment: "",
|
||||||
|
is_comment: true, // 'reply' => false
|
||||||
|
// 回复数据暂存
|
||||||
|
reply_cache: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["user_info", "settings",'bar_state'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(["setUserInfo", "setSettings", "setBarState"]),
|
||||||
|
formatDateTime,
|
||||||
|
// 修改md-app的最小高度
|
||||||
|
changeFixed(clientHeight) {
|
||||||
|
//动态修改样式
|
||||||
|
this.$refs.detail.children[0].style.minHeight = clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.style.maxHeight =
|
||||||
|
clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.style.minHeight =
|
||||||
|
clientHeight - 32 + "px";
|
||||||
|
window.document.documentElement.setAttribute(
|
||||||
|
"data-theme",
|
||||||
|
this.settings.is_dark_mode ? "dark" : "light"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
init() {
|
||||||
|
// 刷新vuex
|
||||||
|
this.$store.replaceState(
|
||||||
|
Object.assign(
|
||||||
|
this.$store.state,
|
||||||
|
JSON.parse(localStorage.getItem("storeState"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// 底部状态栏状态设置
|
||||||
|
this.setBarState([false, this]);
|
||||||
|
// 获取id
|
||||||
|
let id = this.$route.query.id;
|
||||||
|
// 格式校验
|
||||||
|
if (/\d{16}/.test(id)) {
|
||||||
|
this.getDetail(id);
|
||||||
|
} else {
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 返回到主页
|
||||||
|
back() {
|
||||||
|
this.$router.replace("/home");
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取详细信息
|
||||||
|
getDetail(id) {
|
||||||
|
let url = `/detail?id=${id}`;
|
||||||
|
this.loading_switch = true;
|
||||||
|
api
|
||||||
|
.get(url)
|
||||||
|
.then(res => {
|
||||||
|
this.loading_switch = false;
|
||||||
|
this.content = res.data.content;
|
||||||
|
console.log(this.content);
|
||||||
|
console.log("信息获取成功,详情覆写成功");
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
this.loading_switch = false;
|
||||||
|
if (err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`);
|
||||||
|
} else {
|
||||||
|
this.message("网络错误,请稍候重试");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 调用snackBar
|
||||||
|
message(msg) {
|
||||||
|
this.snakebar_msg = msg;
|
||||||
|
this.show_snackbar = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
targetReply(commentid, reply_nick) {
|
||||||
|
this.reply_cache = {
|
||||||
|
commentid,
|
||||||
|
reply_nick
|
||||||
|
};
|
||||||
|
this.is_comment = false;
|
||||||
|
this.comment_dialog_switch = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 评论
|
||||||
|
commentSubmit() {
|
||||||
|
this.loading_switch = true;
|
||||||
|
this.comment = this.comment.trim();
|
||||||
|
if (!this.comment || this.comment.length > 30) {
|
||||||
|
console.log("内容校验失败");
|
||||||
|
this.message("请确保字数在1到30之间");
|
||||||
|
this.comment = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let data;
|
||||||
|
if (this.is_comment) {
|
||||||
|
data = {
|
||||||
|
content: {
|
||||||
|
user_info: {
|
||||||
|
openid: this.user_info.openid,
|
||||||
|
nick: this.user_info.nick
|
||||||
|
},
|
||||||
|
content: this.comment,
|
||||||
|
create_time: new Date().getTime()
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
is_comment: true,
|
||||||
|
lafid: this.content.id,
|
||||||
|
openid: this.content.user_info.openid
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
data = {
|
||||||
|
content: {
|
||||||
|
user_info: {
|
||||||
|
openid: this.user_info.openid,
|
||||||
|
nick: this.user_info.nick
|
||||||
|
},
|
||||||
|
content: `@${this.reply_cache.reply_nick}: ${this.comment}`,
|
||||||
|
create_time: new Date().getTime()
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
is_comment: false,
|
||||||
|
lafid: this.content.id,
|
||||||
|
openid: this.content.user_info.openid,
|
||||||
|
commentid: this.reply_cache.commentid
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
console.log("上传信息准备完成");
|
||||||
|
console.log(data);
|
||||||
|
api
|
||||||
|
.post("/comment", data)
|
||||||
|
.then(res => {
|
||||||
|
let msg = this.is_comment ? "评论成功" : "回复成功";
|
||||||
|
console.log(msg);
|
||||||
|
this.loading_switch = false;
|
||||||
|
this.reply_cache = null;
|
||||||
|
this.is_comment = true;
|
||||||
|
this.comment = "";
|
||||||
|
this.message(msg);
|
||||||
|
this.getDetail(this.content.id);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
this.loading_switch = false;
|
||||||
|
if (err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`);
|
||||||
|
} else {
|
||||||
|
this.message("网络错误,请稍候重试");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 取消输入
|
||||||
|
commentCancel() {
|
||||||
|
this.reply_cache = null;
|
||||||
|
this.is_comment = true;
|
||||||
|
this.comment = "";
|
||||||
|
},
|
||||||
|
// 关闭失物招领
|
||||||
|
closeLaf() {
|
||||||
|
let data = {
|
||||||
|
openid: this.user_info.openid,
|
||||||
|
id: this.content.id
|
||||||
|
};
|
||||||
|
console.log("上传信息准备完成");
|
||||||
|
console.log(data);
|
||||||
|
api
|
||||||
|
.delete("/close", { data })
|
||||||
|
.then(res => {
|
||||||
|
this.message("关闭成功");
|
||||||
|
this.getDetail(this.content.id);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
this.loading_switch = false;
|
||||||
|
if (err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`);
|
||||||
|
} else {
|
||||||
|
this.message("网络错误,请稍候重试");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取浏览器可视区域高度
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
//document.body.clientWidth;
|
||||||
|
window.onresize = function temp() {
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
setHtmlFontSize();
|
||||||
|
}.bind(this);
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.addEventListener(
|
||||||
|
"scroll",
|
||||||
|
this.scroll
|
||||||
|
);
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 如果 `clientHeight` 发生改变,这个函数就会运行
|
||||||
|
clientHeight: function() {
|
||||||
|
this.changeFixed(this.clientHeight);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {},
|
||||||
|
components: {}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss" type="text/scss">
|
||||||
|
@import "../../style/main";
|
||||||
|
.detail {
|
||||||
|
width: 100%;
|
||||||
|
// max-width: 500px;
|
||||||
|
min-height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
// margin: 0 auto;
|
||||||
|
.expand {
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-height: 0.8rem !important;
|
||||||
|
margin: 0.5rem 16px !important;
|
||||||
|
}
|
||||||
|
.login-submit {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0.5rem 0 !important;
|
||||||
|
}
|
||||||
|
.md-toolbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.md-toolbar-row {
|
||||||
|
order: 12;
|
||||||
|
// margin-bottom: .3rem !important;
|
||||||
|
}
|
||||||
|
.md-toolbar-section-start,
|
||||||
|
.md-toolbar-section-end,
|
||||||
|
.md-toolbar-row {
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
.md-toolbar-row {
|
||||||
|
margin-top: -10px;
|
||||||
|
}
|
||||||
|
.md-speed-dial.md-bottom-right {
|
||||||
|
position: fixed !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Demo purposes only
|
||||||
|
.md-drawer {
|
||||||
|
width: 240px;
|
||||||
|
max-width: calc(100vw - 125px);
|
||||||
|
}
|
||||||
|
.md-app-scroller > div {
|
||||||
|
overflow-y: scroll !important;
|
||||||
|
}
|
||||||
|
.face {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.page-title {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
line-height: 56px;
|
||||||
|
}
|
||||||
|
.sroll-top-area {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
.md-bottom-bar.md-type-fixed .md-bottom-bar-item {
|
||||||
|
max-width: 1000px !important;
|
||||||
|
}
|
||||||
|
.md-card-example {
|
||||||
|
.md-subhead {
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
.md-icon {
|
||||||
|
$size: 16px;
|
||||||
|
width: $size;
|
||||||
|
min-width: $size;
|
||||||
|
height: $size;
|
||||||
|
font-size: $size !important;
|
||||||
|
margin-right: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.md-app-content .md-card {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
height: 5rem;
|
||||||
|
width: 5rem;
|
||||||
|
margin-top: -2.5rem;
|
||||||
|
margin-left: -2.5rem;
|
||||||
|
}
|
||||||
|
.md-list-item-text p {
|
||||||
|
word-wrap: break-word !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
white-space: normal !important;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
}
|
||||||
|
</style>
|
481
src/views/Home/Home.vue
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
<template>
|
||||||
|
<div class="home" ref="home">
|
||||||
|
<md-app md-mode="fixed">
|
||||||
|
<md-app-toolbar class="md-primary">
|
||||||
|
<div class="md-toolbar-section-start">
|
||||||
|
<span class="md-title page-title">曳光</span>
|
||||||
|
</div>
|
||||||
|
<md-tabs
|
||||||
|
class="md-primary"
|
||||||
|
style="flex: 1"
|
||||||
|
md-alignment="centered"
|
||||||
|
:md-active-tab="page_type"
|
||||||
|
>
|
||||||
|
<md-tab id="lost" md-label="失物" @click="page_type = 'lost'"></md-tab>
|
||||||
|
<md-tab id="found" md-label="招领" @click="page_type = 'found'"></md-tab>
|
||||||
|
</md-tabs>
|
||||||
|
<div class="md-toolbar-section-end">
|
||||||
|
<div class="sroll-top-area"></div>
|
||||||
|
<md-button class="md-icon-button" @click="switchSearch()">
|
||||||
|
<md-icon>search</md-icon>
|
||||||
|
</md-button>
|
||||||
|
</div>
|
||||||
|
<div class="md-toolbar-row" v-if="search_start">
|
||||||
|
<md-autocomplete
|
||||||
|
class="search"
|
||||||
|
v-model="search_content"
|
||||||
|
:md-options="current_title"
|
||||||
|
md-layout="box"
|
||||||
|
>
|
||||||
|
<label>检索标题</label>
|
||||||
|
</md-autocomplete>
|
||||||
|
</div>
|
||||||
|
</md-app-toolbar>
|
||||||
|
<md-app-content>
|
||||||
|
<v-touch
|
||||||
|
@swiperight="page_type = 'lost'"
|
||||||
|
@swipeleft="page_type = 'found'"
|
||||||
|
:swipe-options="{ direction: 'horizontal' }"
|
||||||
|
>
|
||||||
|
<div ref="list_placeholder" :style="`height:${search_start ? '102' : '56'}px`"></div>
|
||||||
|
|
||||||
|
<md-progress-bar
|
||||||
|
v-if="loading_switch"
|
||||||
|
md-mode="indeterminate"
|
||||||
|
:style="`position: absolute; top: ${search_start ? '102' : '56'}px; left: 0; width: 100%;`"
|
||||||
|
></md-progress-bar>
|
||||||
|
<template v-if="page_type == 'lost'">
|
||||||
|
<!-- 空内容 -->
|
||||||
|
<md-empty-state
|
||||||
|
v-if="show_list.length == 0"
|
||||||
|
class="md-primary"
|
||||||
|
md-icon="done"
|
||||||
|
md-label="暂无内容"
|
||||||
|
md-description="当前并没有失物内容,或许你可以刷新一下"
|
||||||
|
></md-empty-state>
|
||||||
|
<template v-else>
|
||||||
|
<md-content
|
||||||
|
v-for="(item, index) in show_list"
|
||||||
|
:key="index"
|
||||||
|
@click="turnToDetail(item.id)"
|
||||||
|
>
|
||||||
|
<md-card class="md-card-example">
|
||||||
|
<md-card-area md-inset>
|
||||||
|
<md-card-media md-ratio="16:9">
|
||||||
|
<img :src="`https://yg.canary.moe/photo/${item.img_url}`" />
|
||||||
|
</md-card-media>
|
||||||
|
|
||||||
|
<md-card-header>
|
||||||
|
<h2 class="md-subheading">{{item.title}}</h2>
|
||||||
|
<div class="md-subhead">
|
||||||
|
<md-icon>access_time</md-icon>
|
||||||
|
<span>{{formatDateTime(item.create_time)}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-subhead">
|
||||||
|
<md-icon>location_on</md-icon>
|
||||||
|
<span>{{item.total_addr}}</span>
|
||||||
|
</div>
|
||||||
|
</md-card-header>
|
||||||
|
</md-card-area>
|
||||||
|
</md-card>
|
||||||
|
</md-content>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-if="page_type == 'found'">
|
||||||
|
<!-- 空内容 -->
|
||||||
|
<md-empty-state
|
||||||
|
v-if="show_list.length == 0"
|
||||||
|
class="md-primary"
|
||||||
|
md-icon="done"
|
||||||
|
md-label="暂无内容"
|
||||||
|
md-description="当前并没有招领内容,或许你可以刷新一下"
|
||||||
|
></md-empty-state>
|
||||||
|
<template v-else>
|
||||||
|
<md-content
|
||||||
|
v-for="(item, index) in show_list"
|
||||||
|
:key="index"
|
||||||
|
@click="turnToDetail(item.id)"
|
||||||
|
>
|
||||||
|
<md-card class="md-card-example">
|
||||||
|
<md-card-area md-inset>
|
||||||
|
<md-card-media md-ratio="16:9">
|
||||||
|
<img :src="`https://yg.canary.moe/photo/${item.img_url}`" />
|
||||||
|
</md-card-media>
|
||||||
|
|
||||||
|
<md-card-header>
|
||||||
|
<h2 class="md-subheading">{{item.title}}</h2>
|
||||||
|
<div class="md-subhead">
|
||||||
|
<md-icon>access_time</md-icon>
|
||||||
|
<span>{{formatDateTime(item.create_time)}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="md-subhead">
|
||||||
|
<md-icon>location_on</md-icon>
|
||||||
|
<span>{{item.total_addr}}</span>
|
||||||
|
</div>
|
||||||
|
</md-card-header>
|
||||||
|
</md-card-area>
|
||||||
|
</md-card>
|
||||||
|
</md-content>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<md-speed-dial class="md-bottom-right" style="margin-bottom: 56px; z-index:1000;">
|
||||||
|
<md-speed-dial-target class="md-primary" @click="getLostAndFount(true)">
|
||||||
|
<md-icon>cached</md-icon>
|
||||||
|
</md-speed-dial-target>
|
||||||
|
</md-speed-dial>
|
||||||
|
<md-snackbar
|
||||||
|
md-position="center"
|
||||||
|
:md-active.sync="show_snackbar"
|
||||||
|
:md-duration="1500"
|
||||||
|
md-persistent
|
||||||
|
>
|
||||||
|
<span>{{ snakebar_msg }}</span>
|
||||||
|
</md-snackbar>
|
||||||
|
<div :style="`height:56px`"></div>
|
||||||
|
</v-touch>
|
||||||
|
</md-app-content>
|
||||||
|
</md-app>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import { mapState, mapActions } from "vuex";
|
||||||
|
import { setHtmlFontSize } from "@/utils/px2rem.js";
|
||||||
|
import { api } from "@/axios/fetch.js";
|
||||||
|
import { formatDateTime } from "@/utils/formatTime.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Home",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 显示高度,控制md-app的最小高度,防止抽屉高度塌陷
|
||||||
|
clientHeight: "",
|
||||||
|
// snackbar控制
|
||||||
|
show_snackbar: false,
|
||||||
|
snakebar_msg: "",
|
||||||
|
// 加载控制
|
||||||
|
loading_switch: false,
|
||||||
|
// 搜索框当前检索列表
|
||||||
|
current_title: [],
|
||||||
|
// 搜索输入内容
|
||||||
|
search_content: "",
|
||||||
|
// 搜索开始
|
||||||
|
search_start: false,
|
||||||
|
// 显示的密码列表
|
||||||
|
show_list: [],
|
||||||
|
// 页面类型
|
||||||
|
page_type: "lost",
|
||||||
|
// 失物标题
|
||||||
|
lost_title: [],
|
||||||
|
// 招领标题
|
||||||
|
found_title: [],
|
||||||
|
// 失物列表
|
||||||
|
const_lost_list: [],
|
||||||
|
// 招领列表
|
||||||
|
const_found_list: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["user_info", "settings", "laf"])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(["setUserInfo", "setSettings", "setLaf", "setBarState"]),
|
||||||
|
// 格式化时间
|
||||||
|
formatDateTime,
|
||||||
|
// 修改md-app的最小高度
|
||||||
|
changeFixed(clientHeight) {
|
||||||
|
//动态修改样式
|
||||||
|
this.$refs.home.children[0].style.minHeight = clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.style.maxHeight =
|
||||||
|
clientHeight + "px";
|
||||||
|
this.$refs.list_placeholder.parentNode.style.minHeight =
|
||||||
|
clientHeight - 32 + "px";
|
||||||
|
window.document.documentElement.setAttribute(
|
||||||
|
"data-theme",
|
||||||
|
this.settings.is_dark_mode ? "dark" : "light"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
init(from_created = true) {
|
||||||
|
// 刷新vuex
|
||||||
|
this.$store.replaceState(
|
||||||
|
Object.assign(
|
||||||
|
this.$store.state,
|
||||||
|
JSON.parse(localStorage.getItem("storeState"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// 底部状态栏状态设置
|
||||||
|
this.setBarState([true, this]);
|
||||||
|
// 获取失物招领信true息
|
||||||
|
if(from_created)
|
||||||
|
this.getLostAndFount();
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取失物招领信息
|
||||||
|
getLostAndFount(force = false) {
|
||||||
|
let now = new Date().getTime();
|
||||||
|
if (!force && this.laf && now - this.laf.time < 1000 * 60) {
|
||||||
|
console.log("当前信息未失效拦截");
|
||||||
|
this.separateData(this.laf.list, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loading_switch = true;
|
||||||
|
api
|
||||||
|
.get("/get")
|
||||||
|
.then(res => {
|
||||||
|
let laf = {
|
||||||
|
list: res.data.list,
|
||||||
|
time: new Date().getTime()
|
||||||
|
};
|
||||||
|
this.setLaf([laf, this]);
|
||||||
|
console.log("列表获取成功,缓存覆写成功");
|
||||||
|
this.separateData(res.data.list);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
this.loading_switch = false;
|
||||||
|
if (err.response && err.response.status != 500) {
|
||||||
|
this.message(`${err.response.status}: ${err.response.data}`);
|
||||||
|
} else {
|
||||||
|
this.message("网络错误,请稍候重试");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 分离数据
|
||||||
|
separateData(list, from_intercept = false) {
|
||||||
|
// 失物列表
|
||||||
|
let lost_list = [];
|
||||||
|
// 招领列表
|
||||||
|
let found_list = [];
|
||||||
|
// 失物标题
|
||||||
|
let lost_title = [];
|
||||||
|
// 招领标题
|
||||||
|
let found_title = [];
|
||||||
|
// 遍历列表
|
||||||
|
for (let item of list) {
|
||||||
|
if (item.type == "lost") {
|
||||||
|
lost_list.push(item);
|
||||||
|
lost_title.push(item.title);
|
||||||
|
} else {
|
||||||
|
found_list.push(item);
|
||||||
|
found_title.push(item.title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.page_type = "lost";
|
||||||
|
this.show_list = lost_list;
|
||||||
|
this.lost_title = lost_title;
|
||||||
|
this.found_title = found_title;
|
||||||
|
this.const_lost_list = lost_list;
|
||||||
|
this.const_found_list = found_list;
|
||||||
|
this.loading_switch = false;
|
||||||
|
console.log("数据分离完成");
|
||||||
|
if (!from_intercept) this.message("刷新成功");
|
||||||
|
},
|
||||||
|
|
||||||
|
// 调用snackBar
|
||||||
|
message(msg) {
|
||||||
|
this.snakebar_msg = msg;
|
||||||
|
this.show_snackbar = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 切换搜索状态
|
||||||
|
switchSearch() {
|
||||||
|
// 没有内容拦截器
|
||||||
|
if (this.show_list.length == 0) {
|
||||||
|
console.log("点击搜索无内容拦截");
|
||||||
|
this.message("没有内容呀~");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.search_start = !this.search_start;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 模糊搜索
|
||||||
|
fuzzySearch(list) {
|
||||||
|
// 空内容拦截器
|
||||||
|
let search_content = this.search_content.trim();
|
||||||
|
if (!search_content) {
|
||||||
|
this.show_list = list;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let search_res = [];
|
||||||
|
for (let item of list) {
|
||||||
|
if (this.generReg(search_content).test(item.title)) {
|
||||||
|
search_res.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.show_list = search_res;
|
||||||
|
console.log("模糊搜索完成");
|
||||||
|
},
|
||||||
|
|
||||||
|
// 模糊搜索辅助轮
|
||||||
|
generReg(val) {
|
||||||
|
let head = "(.*)(";
|
||||||
|
let tail = ")(.*)";
|
||||||
|
let body = val.split("").join(")(.*)(");
|
||||||
|
return new RegExp(head + body + tail, "i");
|
||||||
|
},
|
||||||
|
|
||||||
|
// 跳转详情
|
||||||
|
turnToDetail(id) {
|
||||||
|
console.log(id);
|
||||||
|
this.$router.push({ path: "/detail", query: { id: id } });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取浏览器可视区域高度
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
//document.body.clientWidth;
|
||||||
|
window.onresize = function temp() {
|
||||||
|
this.clientHeight = `${document.documentElement.clientHeight}`;
|
||||||
|
setHtmlFontSize();
|
||||||
|
}.bind(this);
|
||||||
|
this.$refs.list_placeholder.parentNode.parentNode.addEventListener(
|
||||||
|
"scroll",
|
||||||
|
this.scroll
|
||||||
|
);
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 如果 `clientHeight` 发生改变,这个函数就会运行
|
||||||
|
clientHeight: function() {
|
||||||
|
this.changeFixed(this.clientHeight);
|
||||||
|
},
|
||||||
|
// 如果 `search_start` 发生改变,这个函数就会运行
|
||||||
|
search_start: function() {
|
||||||
|
if (this.search_start) {
|
||||||
|
if (this.page_type == "lost") {
|
||||||
|
this.current_title = JSON.parse(JSON.stringify(this.lost_title));
|
||||||
|
} else {
|
||||||
|
this.current_title = JSON.parse(JSON.stringify(this.found_title));
|
||||||
|
}
|
||||||
|
console.log("搜索阵列展开, 检索列表覆写完成");
|
||||||
|
} else {
|
||||||
|
this.search_content = "";
|
||||||
|
if (this.page_type == "lost") {
|
||||||
|
this.show_list = JSON.parse(JSON.stringify(this.const_lost_list));
|
||||||
|
} else {
|
||||||
|
this.show_list = JSON.parse(JSON.stringify(this.const_found_list));
|
||||||
|
}
|
||||||
|
console.log("搜索阵列关闭,显示列表覆写完成");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 如果 `search_content` 发生改变,这个函数就会运行
|
||||||
|
search_content: function() {
|
||||||
|
// 确保只有在搜索阵列展开后才会进行搜索
|
||||||
|
if (this.search_start) {
|
||||||
|
if (this.page_type == "lost") {
|
||||||
|
this.fuzzySearch(JSON.parse(JSON.stringify(this.const_lost_list)));
|
||||||
|
} else {
|
||||||
|
this.fuzzySearch(JSON.parse(JSON.stringify(this.const_found_list)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 如果 `page_type` 发生改变,这个函数就会运行
|
||||||
|
page_type: function() {
|
||||||
|
if (this.page_type == "lost") {
|
||||||
|
this.show_list = JSON.parse(JSON.stringify(this.const_lost_list));
|
||||||
|
this.current_title = JSON.parse(JSON.stringify(this.lost_title));
|
||||||
|
console.log(`显示列表覆写完成,当前页面性质:${this.page_type}`);
|
||||||
|
} else {
|
||||||
|
this.show_list = JSON.parse(JSON.stringify(this.const_found_list));
|
||||||
|
this.current_title = JSON.parse(JSON.stringify(this.found_title));
|
||||||
|
console.log(`显示列表覆写完成,当前页面性质:${this.page_type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {},
|
||||||
|
components: {},
|
||||||
|
activated() {
|
||||||
|
this.init(false)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss" type="text/scss">
|
||||||
|
@import "../../style/main";
|
||||||
|
.home {
|
||||||
|
width: 100%;
|
||||||
|
// max-width: 500px;
|
||||||
|
min-height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
// margin: 0 auto;
|
||||||
|
.drawer-banner {
|
||||||
|
padding: 1rem 0.3rem 0.3rem 0.3rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: $main-color;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
.default-avatar {
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
}
|
||||||
|
.md-caption {
|
||||||
|
color: #fbfbfb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.md-toolbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.md-toolbar-row {
|
||||||
|
order: 12;
|
||||||
|
}
|
||||||
|
.md-speed-dial.md-bottom-right {
|
||||||
|
position: fixed !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Demo purposes only
|
||||||
|
.md-drawer {
|
||||||
|
width: 240px;
|
||||||
|
max-width: calc(100vw - 125px);
|
||||||
|
}
|
||||||
|
.md-app-scroller > div {
|
||||||
|
overflow-y: scroll !important;
|
||||||
|
}
|
||||||
|
.face {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.page-title {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
line-height: 56px;
|
||||||
|
}
|
||||||
|
.sroll-top-area {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
.md-bottom-bar.md-type-fixed .md-bottom-bar-item {
|
||||||
|
max-width: 1000px !important;
|
||||||
|
}
|
||||||
|
.md-app-content .md-card {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.md-toolbar .md-toolbar-offset {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
.md-toolbar .md-tabs {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
.md-card-example {
|
||||||
|
.md-subhead {
|
||||||
|
.md-icon {
|
||||||
|
$size: 16px;
|
||||||
|
|
||||||
|
width: $size;
|
||||||
|
min-width: $size;
|
||||||
|
height: $size;
|
||||||
|
font-size: $size !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
18
vue.config.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module.exports = {
|
||||||
|
productionSourceMap: false,
|
||||||
|
// publicPath: process.env.NODE_ENV === 'production' ? '/verify/' : '/',
|
||||||
|
pwa: {
|
||||||
|
name: '曳光控制台',
|
||||||
|
themeColor: '#448aff',
|
||||||
|
workboxOptions: {
|
||||||
|
skipWaiting: true
|
||||||
|
},
|
||||||
|
iconPaths: {
|
||||||
|
favicon32: 'favicon.ico',
|
||||||
|
favicon16: 'favicon.ico',
|
||||||
|
appleTouchIcon: 'favicon.ico',
|
||||||
|
maskIcon: 'favicon.ico',
|
||||||
|
msTileImage: 'favicon.ico'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|