文章订阅加密,本地文件上传访问

master
haitao 1 year ago
parent f15a625569
commit 51ef94166c

@ -54,6 +54,12 @@
- 优化:文件上传模块改造,每次上传之前获取上传密钥,每个密钥只能上传一个文件 - 优化:文件上传模块改造,每次上传之前获取上传密钥,每个密钥只能上传一个文件
- 优化个别Bug修复 - 优化个别Bug修复
### 2023年10月1日更新
- 新增:文章加密
- 新增:文章订阅
- 新增:文件上传模块改造,支持多平台(目前对接本地)
- 优化:友人帐及其他模块样式调整
### 首页 ### 首页
![首页](首页.jpg) ![首页](首页.jpg)
@ -110,6 +116,8 @@ npm run build
一定要`Star` 一定要`Star`
注意:[poetize.cn](https://poetize.cn)可能会下线,也可能不会,看缘分吧。
## 欢迎进群一定要Star ## 欢迎进群一定要Star
1. 交流(摸鱼) 1. 交流(摸鱼)
2. 安装部署:互相帮助,争取每个人都零基础拥有自己的个人网站 2. 安装部署:互相帮助,争取每个人都零基础拥有自己的个人网站

@ -5,7 +5,7 @@
<link rel="icon" href="./poetize.jpg" sizes="16x16"> <link rel="icon" href="./poetize.jpg" sizes="16x16">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Sara</title> <title>Poetize</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script> <script src="https://cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script>

@ -53,6 +53,10 @@
<el-input maxlength="30" v-model="article.password"></el-input> <el-input maxlength="30" v-model="article.password"></el-input>
</el-form-item> </el-form-item>
<el-form-item v-if="article.viewStatus === false" label="密码提示" prop="tips">
<el-input maxlength="60" v-model="article.tips"></el-input>
</el-form-item>
<el-form-item label="封面" prop="articleCover"> <el-form-item label="封面" prop="articleCover">
<div style="display: flex"> <div style="display: flex">
<el-input v-model="article.articleCover"></el-input> <el-input v-model="article.articleCover"></el-input>
@ -112,6 +116,7 @@
recommendStatus: false, recommendStatus: false,
viewStatus: true, viewStatus: true,
password: "", password: "",
tips: "",
articleCover: "", articleCover: "",
sortId: null, sortId: null,
labelId: null labelId: null
@ -176,11 +181,39 @@
suffix = file.name.substring(file.name.lastIndexOf('.')); suffix = file.name.substring(file.name.lastIndexOf('.'));
} }
let key = "articlePicture" + "/" + this.$store.state.currentAdmin.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentAdmin.id + new Date().getTime() + Math.floor(Math.random() * 1000) + suffix; let key = "articlePicture" + "/" + this.$store.state.currentAdmin.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentAdmin.id + new Date().getTime() + Math.floor(Math.random() * 1000) + suffix;
let storeType = localStorage.getItem("defaultStoreType");
let fd = new FormData(); let fd = new FormData();
fd.append("file", file); fd.append("file", file);
fd.append("key", key); fd.append("key", key);
fd.append("relativePath", key);
fd.append("type", "articlePicture");
fd.append("storeType", storeType);
this.$http.get(this.$constant.baseURL + "/qiniu/getUpToken", {key: key}, true) if (storeType === "local") {
this.saveLocal(pos, fd);
} else if (storeType === "qiniu") {
this.saveQiniu(pos, fd);
}
},
saveLocal(pos, fd) {
this.$http.upload(this.$constant.baseURL + "/resource/upload", fd, true)
.then((res) => {
if (!this.$common.isEmpty(res.data)) {
let url = res.data;
this.$refs.md.$img2Url(pos, url);
}
})
.catch((error) => {
this.$message({
message: error.message,
type: "error"
});
});
},
saveQiniu(pos, fd) {
this.$http.get(this.$constant.baseURL + "/qiniu/getUpToken", {key: fd.get("key")}, true)
.then((res) => { .then((res) => {
if (!this.$common.isEmpty(res.data)) { if (!this.$common.isEmpty(res.data)) {
fd.append("token", res.data); fd.append("token", res.data);
@ -189,7 +222,8 @@
.then((res) => { .then((res) => {
if (!this.$common.isEmpty(res.key)) { if (!this.$common.isEmpty(res.key)) {
let url = this.$constant.qiniuDownload + res.key; let url = this.$constant.qiniuDownload + res.key;
this.$common.saveResource(this, "articlePicture", url, file.size, file.type, true); let file = fd.get("file");
this.$common.saveResource(this, "articlePicture", url, file.size, file.type, "qiniu", true);
this.$refs.md.$img2Url(pos, url); this.$refs.md.$img2Url(pos, url);
} }
}) })

@ -58,6 +58,7 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="mimeType" label="类型" align="center"></el-table-column> <el-table-column prop="mimeType" label="类型" align="center"></el-table-column>
<el-table-column prop="storeType" label="存储平台" align="center"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center"></el-table-column> <el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
<el-table-column label="操作" width="180" align="center"> <el-table-column label="操作" width="180" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
@ -85,7 +86,19 @@
destroy-on-close destroy-on-close
center> center>
<div> <div>
<div style="display: flex;margin-bottom: 10px">
<div style="line-height: 40px">存储平台</div>
<el-select v-model="storeType" placeholder="存储平台" style="width: 120px">
<el-option
v-for="(item, i) in storeTypes"
:key="i"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<uploadPicture :isAdmin="true" :prefix="pagination.resourceType" @addPicture="addPicture" :maxSize="5" <uploadPicture :isAdmin="true" :prefix="pagination.resourceType" @addPicture="addPicture" :maxSize="5"
:storeType="storeType"
:maxNumber="10"></uploadPicture> :maxNumber="10"></uploadPicture>
</div> </div>
</el-dialog> </el-dialog>
@ -109,7 +122,12 @@
resourceType: "" resourceType: ""
}, },
resources: [], resources: [],
resourceDialog: false resourceDialog: false,
storeTypes: [
{label: "服务器", value: "local"},
{label: "七牛云", value: "qiniu"}
],
storeType: localStorage.getItem("defaultStoreType")
} }
}, },

@ -99,7 +99,7 @@
<div style="margin-bottom: 5px">标题</div> <div style="margin-bottom: 5px">标题</div>
<el-input maxlength="60" v-model="resourcePath.title"></el-input> <el-input maxlength="60" v-model="resourcePath.title"></el-input>
<div style="margin-top: 10px;margin-bottom: 5px">分类</div> <div style="margin-top: 10px;margin-bottom: 5px">分类</div>
<el-input :disabled="!['lovePhoto', 'funny', 'favorites'].includes(resourcePath.type)" <el-input :disabled="!['friendUrl', 'lovePhoto', 'funny', 'favorites'].includes(resourcePath.type)"
maxlength="30" v-model="resourcePath.classify"></el-input> maxlength="30" v-model="resourcePath.classify"></el-input>
<div style="margin-top: 10px;margin-bottom: 5px">简介</div> <div style="margin-top: 10px;margin-bottom: 5px">简介</div>
<el-input :disabled="!['friendUrl', 'favorites'].includes(resourcePath.type)" <el-input :disabled="!['friendUrl', 'favorites'].includes(resourcePath.type)"

@ -1,187 +1,214 @@
<template> <template>
<div v-if="!$common.isEmpty(article)"> <div>
<!-- 封面 --> <div v-if="!$common.isEmpty(article)">
<div class="article-head my-animation-slide-top"> <!-- 封面 -->
<!-- 背景图片 --> <div class="article-head my-animation-slide-top">
<el-image class="article-image my-el-image" <!-- 背景图片 -->
v-once <el-image class="article-image my-el-image"
lazy v-once
:src="!$common.isEmpty(article.articleCover)?article.articleCover:$constant.random_image+new Date()+Math.floor(Math.random()*10)" lazy
fit="cover"> :src="!$common.isEmpty(article.articleCover)?article.articleCover:$constant.random_image+new Date()+Math.floor(Math.random()*10)"
<div slot="error" class="image-slot"> fit="cover">
<div class="article-image"></div> <div slot="error" class="image-slot">
<div class="article-image"></div>
</div>
</el-image>
<!-- 文章信息 -->
<div class="article-info-container">
<div class="article-title">{{ article.articleTitle }}</div>
<div class="article-info">
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path
d="M510.4 65.5l259.69999999 0 1e-8 266.89999999c0 147.50000001-116.2 266.89999999-259.7 266.90000001-143.4 0-259.7-119.5-259.7-266.90000001 0.1-147.5 116.3-266.9 259.7-266.89999999z"
fill="#FF9FCF"></path>
<path
d="M698.4 525.2l-13 0c53-48.4 86.5-117.8 86.5-195.20000001 0-10.2-0.7-20.3-1.8-30.19999999C613.8 377.50000001 438.6 444.9 266 437.7c15 33.4 36.7 63.1 63.5 87.5l-5.3 0c-122.6 0-225.5 88.1-248.8 204.1C340 677.2 597.7 609.2 862.2 585.7c-44.3-37.6-101.5-60.5-163.8-60.5z"
fill="#FF83BB"></path>
<path
d="M862.2 585.7C597.7 609.2 340 677.2 75.4 729.3c-3.2 16.1-5 32.6-5 49.6 0 99.8 81.7 181.5 181.5 181.5l518.6 0c99.8 0 181.5-81.7 181.5-181.5 0.1-77.2-35-146.5-89.8-193.2z"
fill="#FF5390"></path>
<path
d="M770.1 299.8C755.1 168 643.3 65.5 507.4 65.5c-146.1 0-264.5 118.4-264.5 264.5 0 38.4 8.3 74.8 23.1 107.7 172.6 7.2 347.8-60.2 504.1-137.9z"
fill="#FF9FCF"></path>
<path
d="M436.4 282.1c0 24.1-19.6 43.7-43.7 43.7S349 306.2 349 282.1s19.6-43.7 43.7-43.7c24.19999999 0 43.7 19.6 43.7 43.7z"
fill="#FFFFFF"></path>
<path d="M625 282.1m-43.7 0a43.7 43.7 0 1 0 87.4 0 43.7 43.7 0 1 0-87.4 0Z" fill="#FFFFFF"></path>
</svg>
<span>&nbsp;{{ article.username }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#409EFF"></path>
<path
d="M654.222222 256c-17.066667 0-28.444444 11.377778-28.444444 28.444444v56.888889c0 17.066667 11.377778 28.444444 28.444444 28.444445s28.444444-11.377778 28.444445-28.444445v-56.888889c0-17.066667-11.377778-28.444444-28.444445-28.444444zM369.777778 256c-17.066667 0-28.444444 11.377778-28.444445 28.444444v56.888889c0 17.066667 11.377778 28.444444 28.444445 28.444445s28.444444-11.377778 28.444444-28.444445v-56.888889c0-17.066667-11.377778-28.444444-28.444444-28.444444z"
fill="#FFFFFF"></path>
<path
d="M725.333333 312.888889H711.111111v28.444444c0 31.288889-25.6 56.888889-56.888889 56.888889s-56.888889-25.6-56.888889-56.888889v-28.444444h-170.666666v28.444444c0 31.288889-25.6 56.888889-56.888889 56.888889s-56.888889-25.6-56.888889-56.888889v-28.444444h-14.222222c-22.755556 0-42.666667 19.911111-42.666667 42.666667v341.333333c0 22.755556 19.911111 42.666667 42.666667 42.666667h426.666666c22.755556 0 42.666667-19.911111 42.666667-42.666667v-341.333333c0-22.755556-19.911111-42.666667-42.666667-42.666667zM426.666667 654.222222h-56.888889c-17.066667 0-28.444444-11.377778-28.444445-28.444444s11.377778-28.444444 28.444445-28.444445h56.888889c17.066667 0 28.444444 11.377778 28.444444 28.444445s-11.377778 28.444444-28.444444 28.444444z m227.555555 0h-56.888889c-17.066667 0-28.444444-11.377778-28.444444-28.444444s11.377778-28.444444 28.444444-28.444445h56.888889c17.066667 0 28.444444 11.377778 28.444445 28.444445s-11.377778 28.444444-28.444445 28.444444z m0-113.777778h-56.888889c-17.066667 0-28.444444-11.377778-28.444444-28.444444s11.377778-28.444444 28.444444-28.444444h56.888889c17.066667 0 28.444444 11.377778 28.444445 28.444444s-11.377778 28.444444-28.444445 28.444444z"
fill="#FFFFFF"></path>
</svg>
<span>&nbsp;{{ article.createTime }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path d="M14.656 512a497.344 497.344 0 1 0 994.688 0 497.344 497.344 0 1 0-994.688 0z"
fill="#FF0000"></path>
<path
d="M374.976 872.64c-48.299-100.032-22.592-157.44 14.421-211.37 40.448-58.966 51.115-117.611 51.115-117.611s31.659 41.386 19.115 106.005c56.149-62.72 66.816-162.133 58.325-200.405 127.317 88.746 181.59 281.002 108.181 423.381C1016 652.501 723.093 323.2 672.277 285.867c16.939 37.333 20.054 100.032-14.101 130.474-58.027-219.84-201.664-265.002-201.664-265.002 16.96 113.536-61.781 237.397-137.344 330.24-2.816-45.163-5.632-76.544-29.483-119.808-5.333 82.176-68.373 149.269-85.29 231.445-22.912 111.637 17.237 193.173 170.581 279.424z"
fill="#FFFFFF"></path>
</svg>
<span>&nbsp;{{ article.viewCount }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path
d="M113.834667 291.84v449.194667a29.013333 29.013333 0 0 0 28.842666 29.013333h252.928v90.453333l160.597334-90.453333h252.928a29.013333 29.013333 0 0 0 29.013333-29.013333V291.84a29.013333 29.013333 0 0 0-29.013333-29.013333h-665.6a29.013333 29.013333 0 0 0-29.696 29.013333z"
fill="#FFDEAD"></path>
<path
d="M809.130667 262.826667h-665.6a29.013333 29.013333 0 0 0-28.842667 29.013333v40.106667a29.013333 29.013333 0 0 1 28.842667-29.013334h665.6a29.013333 29.013333 0 0 1 29.013333 29.013334V291.84a29.013333 29.013333 0 0 0-29.013333-29.013333z"
fill="#FFF3DB"></path>
<path
d="M556.202667 770.048h252.928a29.013333 29.013333 0 0 0 29.013333-29.013333V362.837333s-59.733333 392.533333-724.309333 314.709334v63.488a29.013333 29.013333 0 0 0 28.842666 29.013333h253.098667v90.453333z"
fill="#F2C182"></path>
<path
d="M619.008 632.32l101.888-35.157333-131.754667-76.117334 29.866667 111.274667zM891.904 148.992a61.44 61.44 0 0 0-84.138667 22.528l-19.968 34.133333 106.666667 61.610667 19.968-34.133333a61.781333 61.781333 0 0 0-22.528-84.138667z"
fill="#69BAF9"></path>
<path d="M775.338667 198.775467l131.669333 76.032-186.026667 322.218666-131.6864-76.032z"
fill="#F7FBFF"></path>
<path
d="M775.168 198.826667l-5.290667 9.216 59.221334 34.133333a34.133333 34.133333 0 0 1 12.458666 46.592l-139.946666 242.346667a34.133333 34.133333 0 0 1-46.762667 12.629333l-59.050667-34.133333-6.656 11.434666 88.746667 51.2L720.896 597.333333l186.026667-322.56z"
fill="#D8E3F0"></path>
<path
d="M616.448 622.592l2.56 9.728 101.888-35.157333-44.885333-25.941334-59.562667 51.370667zM891.904 148.992c-1.024 0-2.218667-0.853333-3.242667-1.536A61.610667 61.610667 0 0 1 887.466667 204.8l-19.968 34.133333-73.728-42.496-5.12 8.704 106.666666 61.610667 19.968-34.133333a61.781333 61.781333 0 0 0-23.381333-83.626667z"
fill="#599ED4"></path>
<path
d="M265.898667 417.621333H494.933333a17.066667 17.066667 0 1 0 0-34.133333H265.898667a17.066667 17.066667 0 1 0 0 34.133333zM265.898667 533.504H494.933333a17.066667 17.066667 0 0 0 0-34.133333H265.898667a17.066667 17.066667 0 0 0 0 34.133333z"
fill="#3D3D63"></path>
<path
d="M959.488 354.645333a99.84 99.84 0 0 0-23.722667-127.488 78.677333 78.677333 0 0 0-142.848-64.170666l-11.605333 20.138666a17.066667 17.066667 0 0 0-20.821333 7.168l-32.085334 55.466667H142.677333a46.250667 46.250667 0 0 0-45.909333 46.08v449.194667a46.08 46.08 0 0 0 45.909333 46.08h236.032v73.386666a17.066667 17.066667 0 0 0 8.362667 14.848 17.066667 17.066667 0 0 0 8.704 2.218667 17.066667 17.066667 0 0 0 8.362667-2.218667l156.672-88.234666h248.32a46.08 46.08 0 0 0 46.08-46.08V398.677333L921.6 283.306667a17.066667 17.066667 0 0 0-4.266667-21.504l1.877334-3.413334a65.365333 65.365333 0 0 1 10.410666 79.189334l-53.077333 91.989333a56.832 56.832 0 0 0 20.821333 77.653333 17.066667 17.066667 0 0 0 24.234667-6.314666 17.066667 17.066667 0 0 0-6.997333-23.04 23.04 23.04 0 0 1-8.362667-31.061334z m-138.410667 386.389334a11.946667 11.946667 0 0 1-11.946666 11.946666H556.202667a17.066667 17.066667 0 0 0-8.362667 2.218667l-134.997333 76.117333v-61.269333a17.066667 17.066667 0 0 0-17.066667-17.066667H142.677333a11.946667 11.946667 0 0 1-11.776-11.946666V291.84a11.946667 11.946667 0 0 1 11.776-11.946667h565.930667L574.464 512a17.066667 17.066667 0 0 0-1.706667 12.970667L597.333333 615.253333H265.898667a17.066667 17.066667 0 1 0 0 34.133334h352.938666a17.066667 17.066667 0 0 0 5.802667 0l102.4-35.328a17.066667 17.066667 0 0 0 9.216-7.509334l85.333333-147.968z m-204.8-184.661334l63.829334 36.864-49.322667 17.066667z m206.848-170.666666v1.365333l-108.373333 186.709333-102.4-59.050666L781.482667 221.866667l102.4 59.050666z m76.458667-161.28L887.466667 244.224l-76.970667-44.373333 11.264-19.797334a44.544 44.544 0 1 1 77.141333 44.544z"
fill="#3D3D63"></path>
</svg>
<span>&nbsp;{{ article.commentCount }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path
d="M510.671749 348.792894S340.102978 48.827055 134.243447 254.685563C-97.636714 486.565724 510.671749 913.435858 510.671749 913.435858s616.107079-419.070494 376.428301-658.749272c-194.095603-194.096626-376.428302 94.106308-376.428301 94.106308z"
fill="#FF713C"></path>
<path
d="M510.666632 929.674705c-3.267417 0-6.534833-0.983397-9.326413-2.950192-16.924461-11.872399-414.71121-293.557896-435.220312-529.448394-5.170766-59.482743 13.879102-111.319341 56.643068-154.075121 51.043536-51.043536 104.911398-76.930113 160.095231-76.930114 112.524796 0 196.878996 106.48115 228.475622 153.195078 33.611515-45.214784 122.406864-148.20646 234.04343-148.20646 53.930283 0 105.46603 24.205285 153.210428 71.941496 45.063335 45.063335 64.954361 99.200326 59.133795 160.920016C935.306982 641.685641 536.758893 915.327952 519.80271 926.859589a16.205077 16.205077 0 0 1-9.136078 2.815116zM282.857183 198.75574c-46.25344 0-92.396363 22.682605-137.127124 67.413365-36.149315 36.157501-51.614541 78.120218-47.25321 128.291898 17.575284 202.089671 352.199481 455.119525 412.332023 499.049037 60.434417-42.86732 395.406538-289.147446 414.567947-492.458945 4.933359-52.344159-11.341303-96.465029-49.759288-134.88199-41.431621-41.423435-85.24243-62.424748-130.242319-62.424748-122.041544 0-220.005716 152.203494-220.989114 153.742547-3.045359 4.806469-8.53335 7.883551-14.101159 7.534603a16.257266 16.257266 0 0 1-13.736863-8.184403c-0.902556-1.587148-91.569532-158.081365-213.690893-158.081364z"
fill="#885F44"></path>
</svg>
<span>&nbsp;{{ article.likeCount }}</span>
</div>
</div> </div>
</el-image>
<!-- 文章信息 --> <div class="article-info-news"
<div class="article-info-container"> @click="weiYanDialogVisible = true"
<div class="article-title">{{ article.articleTitle }}</div> v-if="!$common.isEmpty($store.state.currentUser) && $store.state.currentUser.id === article.userId">
<div class="article-info"> <svg width="30" height="30" viewBox="0 0 1024 1024">
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;"> <path d="M0 0h1024v1024H0V0z" fill="#202425" opacity=".01"></path>
<path
d="M510.4 65.5l259.69999999 0 1e-8 266.89999999c0 147.50000001-116.2 266.89999999-259.7 266.90000001-143.4 0-259.7-119.5-259.7-266.90000001 0.1-147.5 116.3-266.9 259.7-266.89999999z"
fill="#FF9FCF"></path>
<path
d="M698.4 525.2l-13 0c53-48.4 86.5-117.8 86.5-195.20000001 0-10.2-0.7-20.3-1.8-30.19999999C613.8 377.50000001 438.6 444.9 266 437.7c15 33.4 36.7 63.1 63.5 87.5l-5.3 0c-122.6 0-225.5 88.1-248.8 204.1C340 677.2 597.7 609.2 862.2 585.7c-44.3-37.6-101.5-60.5-163.8-60.5z"
fill="#FF83BB"></path>
<path
d="M862.2 585.7C597.7 609.2 340 677.2 75.4 729.3c-3.2 16.1-5 32.6-5 49.6 0 99.8 81.7 181.5 181.5 181.5l518.6 0c99.8 0 181.5-81.7 181.5-181.5 0.1-77.2-35-146.5-89.8-193.2z"
fill="#FF5390"></path>
<path
d="M770.1 299.8C755.1 168 643.3 65.5 507.4 65.5c-146.1 0-264.5 118.4-264.5 264.5 0 38.4 8.3 74.8 23.1 107.7 172.6 7.2 347.8-60.2 504.1-137.9z"
fill="#FF9FCF"></path>
<path
d="M436.4 282.1c0 24.1-19.6 43.7-43.7 43.7S349 306.2 349 282.1s19.6-43.7 43.7-43.7c24.19999999 0 43.7 19.6 43.7 43.7z"
fill="#FFFFFF"></path>
<path d="M625 282.1m-43.7 0a43.7 43.7 0 1 0 87.4 0 43.7 43.7 0 1 0-87.4 0Z" fill="#FFFFFF"></path>
</svg>
<span>&nbsp;{{ article.username }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#409EFF"></path>
<path
d="M654.222222 256c-17.066667 0-28.444444 11.377778-28.444444 28.444444v56.888889c0 17.066667 11.377778 28.444444 28.444444 28.444445s28.444444-11.377778 28.444445-28.444445v-56.888889c0-17.066667-11.377778-28.444444-28.444445-28.444444zM369.777778 256c-17.066667 0-28.444444 11.377778-28.444445 28.444444v56.888889c0 17.066667 11.377778 28.444444 28.444445 28.444445s28.444444-11.377778 28.444444-28.444445v-56.888889c0-17.066667-11.377778-28.444444-28.444444-28.444444z"
fill="#FFFFFF"></path>
<path <path
d="M725.333333 312.888889H711.111111v28.444444c0 31.288889-25.6 56.888889-56.888889 56.888889s-56.888889-25.6-56.888889-56.888889v-28.444444h-170.666666v28.444444c0 31.288889-25.6 56.888889-56.888889 56.888889s-56.888889-25.6-56.888889-56.888889v-28.444444h-14.222222c-22.755556 0-42.666667 19.911111-42.666667 42.666667v341.333333c0 22.755556 19.911111 42.666667 42.666667 42.666667h426.666666c22.755556 0 42.666667-19.911111 42.666667-42.666667v-341.333333c0-22.755556-19.911111-42.666667-42.666667-42.666667zM426.666667 654.222222h-56.888889c-17.066667 0-28.444444-11.377778-28.444445-28.444444s11.377778-28.444444 28.444445-28.444445h56.888889c17.066667 0 28.444444 11.377778 28.444444 28.444445s-11.377778 28.444444-28.444444 28.444444z m227.555555 0h-56.888889c-17.066667 0-28.444444-11.377778-28.444444-28.444444s11.377778-28.444444 28.444444-28.444445h56.888889c17.066667 0 28.444444 11.377778 28.444445 28.444445s-11.377778 28.444444-28.444445 28.444444z m0-113.777778h-56.888889c-17.066667 0-28.444444-11.377778-28.444444-28.444444s11.377778-28.444444 28.444444-28.444444h56.888889c17.066667 0 28.444444 11.377778 28.444445 28.444444s-11.377778 28.444444-28.444445 28.444444z" d="M989.866667 512c0 263.918933-213.947733 477.866667-477.866667 477.866667S34.133333 775.918933 34.133333 512 248.081067 34.133333 512 34.133333s477.866667 213.947733 477.866667 477.866667z"
fill="#FFFFFF"></path> fill="#FF7744"></path>
</svg>
<span>&nbsp;{{ article.createTime }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path d="M14.656 512a497.344 497.344 0 1 0 994.688 0 497.344 497.344 0 1 0-994.688 0z"
fill="#FF0000"></path>
<path <path
d="M374.976 872.64c-48.299-100.032-22.592-157.44 14.421-211.37 40.448-58.966 51.115-117.611 51.115-117.611s31.659 41.386 19.115 106.005c56.149-62.72 66.816-162.133 58.325-200.405 127.317 88.746 181.59 281.002 108.181 423.381C1016 652.501 723.093 323.2 672.277 285.867c16.939 37.333 20.054 100.032-14.101 130.474-58.027-219.84-201.664-265.002-201.664-265.002 16.96 113.536-61.781 237.397-137.344 330.24-2.816-45.163-5.632-76.544-29.483-119.808-5.333 82.176-68.373 149.269-85.29 231.445-22.912 111.637 17.237 193.173 170.581 279.424z" d="M512 221.866667A51.2 51.2 0 0 1 563.2 273.066667v187.733333H750.933333a51.2 51.2 0 0 1 0 102.4h-187.733333V750.933333a51.2 51.2 0 0 1-102.4 0v-187.733333H273.066667a51.2 51.2 0 0 1 0-102.4h187.733333V273.066667A51.2 51.2 0 0 1 512 221.866667z"
fill="#FFFFFF"></path> fill="#FFFFFF"></path>
</svg> </svg>
<span>&nbsp;{{ article.viewCount }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path
d="M113.834667 291.84v449.194667a29.013333 29.013333 0 0 0 28.842666 29.013333h252.928v90.453333l160.597334-90.453333h252.928a29.013333 29.013333 0 0 0 29.013333-29.013333V291.84a29.013333 29.013333 0 0 0-29.013333-29.013333h-665.6a29.013333 29.013333 0 0 0-29.696 29.013333z"
fill="#FFDEAD"></path>
<path
d="M809.130667 262.826667h-665.6a29.013333 29.013333 0 0 0-28.842667 29.013333v40.106667a29.013333 29.013333 0 0 1 28.842667-29.013334h665.6a29.013333 29.013333 0 0 1 29.013333 29.013334V291.84a29.013333 29.013333 0 0 0-29.013333-29.013333z"
fill="#FFF3DB"></path>
<path
d="M556.202667 770.048h252.928a29.013333 29.013333 0 0 0 29.013333-29.013333V362.837333s-59.733333 392.533333-724.309333 314.709334v63.488a29.013333 29.013333 0 0 0 28.842666 29.013333h253.098667v90.453333z"
fill="#F2C182"></path>
<path
d="M619.008 632.32l101.888-35.157333-131.754667-76.117334 29.866667 111.274667zM891.904 148.992a61.44 61.44 0 0 0-84.138667 22.528l-19.968 34.133333 106.666667 61.610667 19.968-34.133333a61.781333 61.781333 0 0 0-22.528-84.138667z"
fill="#69BAF9"></path>
<path d="M775.338667 198.775467l131.669333 76.032-186.026667 322.218666-131.6864-76.032z"
fill="#F7FBFF"></path>
<path
d="M775.168 198.826667l-5.290667 9.216 59.221334 34.133333a34.133333 34.133333 0 0 1 12.458666 46.592l-139.946666 242.346667a34.133333 34.133333 0 0 1-46.762667 12.629333l-59.050667-34.133333-6.656 11.434666 88.746667 51.2L720.896 597.333333l186.026667-322.56z"
fill="#D8E3F0"></path>
<path
d="M616.448 622.592l2.56 9.728 101.888-35.157333-44.885333-25.941334-59.562667 51.370667zM891.904 148.992c-1.024 0-2.218667-0.853333-3.242667-1.536A61.610667 61.610667 0 0 1 887.466667 204.8l-19.968 34.133333-73.728-42.496-5.12 8.704 106.666666 61.610667 19.968-34.133333a61.781333 61.781333 0 0 0-23.381333-83.626667z"
fill="#599ED4"></path>
<path
d="M265.898667 417.621333H494.933333a17.066667 17.066667 0 1 0 0-34.133333H265.898667a17.066667 17.066667 0 1 0 0 34.133333zM265.898667 533.504H494.933333a17.066667 17.066667 0 0 0 0-34.133333H265.898667a17.066667 17.066667 0 0 0 0 34.133333z"
fill="#3D3D63"></path>
<path
d="M959.488 354.645333a99.84 99.84 0 0 0-23.722667-127.488 78.677333 78.677333 0 0 0-142.848-64.170666l-11.605333 20.138666a17.066667 17.066667 0 0 0-20.821333 7.168l-32.085334 55.466667H142.677333a46.250667 46.250667 0 0 0-45.909333 46.08v449.194667a46.08 46.08 0 0 0 45.909333 46.08h236.032v73.386666a17.066667 17.066667 0 0 0 8.362667 14.848 17.066667 17.066667 0 0 0 8.704 2.218667 17.066667 17.066667 0 0 0 8.362667-2.218667l156.672-88.234666h248.32a46.08 46.08 0 0 0 46.08-46.08V398.677333L921.6 283.306667a17.066667 17.066667 0 0 0-4.266667-21.504l1.877334-3.413334a65.365333 65.365333 0 0 1 10.410666 79.189334l-53.077333 91.989333a56.832 56.832 0 0 0 20.821333 77.653333 17.066667 17.066667 0 0 0 24.234667-6.314666 17.066667 17.066667 0 0 0-6.997333-23.04 23.04 23.04 0 0 1-8.362667-31.061334z m-138.410667 386.389334a11.946667 11.946667 0 0 1-11.946666 11.946666H556.202667a17.066667 17.066667 0 0 0-8.362667 2.218667l-134.997333 76.117333v-61.269333a17.066667 17.066667 0 0 0-17.066667-17.066667H142.677333a11.946667 11.946667 0 0 1-11.776-11.946666V291.84a11.946667 11.946667 0 0 1 11.776-11.946667h565.930667L574.464 512a17.066667 17.066667 0 0 0-1.706667 12.970667L597.333333 615.253333H265.898667a17.066667 17.066667 0 1 0 0 34.133334h352.938666a17.066667 17.066667 0 0 0 5.802667 0l102.4-35.328a17.066667 17.066667 0 0 0 9.216-7.509334l85.333333-147.968z m-204.8-184.661334l63.829334 36.864-49.322667 17.066667z m206.848-170.666666v1.365333l-108.373333 186.709333-102.4-59.050666L781.482667 221.866667l102.4 59.050666z m76.458667-161.28L887.466667 244.224l-76.970667-44.373333 11.264-19.797334a44.544 44.544 0 1 1 77.141333 44.544z"
fill="#3D3D63"></path>
</svg>
<span>&nbsp;{{ article.commentCount }}</span>
<span>·</span>
<svg viewBox="0 0 1024 1024" width="14" height="14" style="vertical-align: -2px;">
<path
d="M510.671749 348.792894S340.102978 48.827055 134.243447 254.685563C-97.636714 486.565724 510.671749 913.435858 510.671749 913.435858s616.107079-419.070494 376.428301-658.749272c-194.095603-194.096626-376.428302 94.106308-376.428301 94.106308z"
fill="#FF713C"></path>
<path
d="M510.666632 929.674705c-3.267417 0-6.534833-0.983397-9.326413-2.950192-16.924461-11.872399-414.71121-293.557896-435.220312-529.448394-5.170766-59.482743 13.879102-111.319341 56.643068-154.075121 51.043536-51.043536 104.911398-76.930113 160.095231-76.930114 112.524796 0 196.878996 106.48115 228.475622 153.195078 33.611515-45.214784 122.406864-148.20646 234.04343-148.20646 53.930283 0 105.46603 24.205285 153.210428 71.941496 45.063335 45.063335 64.954361 99.200326 59.133795 160.920016C935.306982 641.685641 536.758893 915.327952 519.80271 926.859589a16.205077 16.205077 0 0 1-9.136078 2.815116zM282.857183 198.75574c-46.25344 0-92.396363 22.682605-137.127124 67.413365-36.149315 36.157501-51.614541 78.120218-47.25321 128.291898 17.575284 202.089671 352.199481 455.119525 412.332023 499.049037 60.434417-42.86732 395.406538-289.147446 414.567947-492.458945 4.933359-52.344159-11.341303-96.465029-49.759288-134.88199-41.431621-41.423435-85.24243-62.424748-130.242319-62.424748-122.041544 0-220.005716 152.203494-220.989114 153.742547-3.045359 4.806469-8.53335 7.883551-14.101159 7.534603a16.257266 16.257266 0 0 1-13.736863-8.184403c-0.902556-1.587148-91.569532-158.081365-213.690893-158.081364z"
fill="#885F44"></path>
</svg>
<span>&nbsp;{{ article.likeCount }}</span>
</div> </div>
</div> </div>
<!-- 文章 -->
<div style="background: var(--background);">
<div class="article-container my-animation-slide-bottom">
<!-- 最新进展 -->
<div v-if="!$common.isEmpty(treeHoleList)" class="process-wrap">
<el-collapse accordion value="1">
<el-collapse-item title="最新进展" name="1">
<process :treeHoleList="treeHoleList" @deleteTreeHole="deleteTreeHole"></process>
</el-collapse-item>
</el-collapse>
<hr>
</div>
<div class="article-info-news" <!-- 文章内容 -->
@click="weiYanDialogVisible = true" <div v-html="articleContentHtml" class="entry-content"></div>
v-if="!$common.isEmpty($store.state.currentUser) && $store.state.currentUser.id === article.userId"> <!-- 最后更新时间 -->
<svg width="30" height="30" viewBox="0 0 1024 1024"> <div class="article-update-time">
<path d="M0 0h1024v1024H0V0z" fill="#202425" opacity=".01"></path> <span>文章最后更新于 {{ article.updateTime }}</span>
<path
d="M989.866667 512c0 263.918933-213.947733 477.866667-477.866667 477.866667S34.133333 775.918933 34.133333 512 248.081067 34.133333 512 34.133333s477.866667 213.947733 477.866667 477.866667z"
fill="#FF7744"></path>
<path
d="M512 221.866667A51.2 51.2 0 0 1 563.2 273.066667v187.733333H750.933333a51.2 51.2 0 0 1 0 102.4h-187.733333V750.933333a51.2 51.2 0 0 1-102.4 0v-187.733333H273.066667a51.2 51.2 0 0 1 0-102.4h187.733333V273.066667A51.2 51.2 0 0 1 512 221.866667z"
fill="#FFFFFF"></path>
</svg>
</div>
</div>
<!-- 文章 -->
<div style="background: var(--background);">
<div class="article-container my-animation-slide-bottom">
<!-- 最新进展 -->
<div v-if="!$common.isEmpty(treeHoleList)" class="process-wrap">
<el-collapse accordion value="1">
<el-collapse-item title="最新进展" name="1">
<process :treeHoleList="treeHoleList" @deleteTreeHole="deleteTreeHole"></process>
</el-collapse-item>
</el-collapse>
<hr>
</div>
<!-- 文章内容 -->
<div v-html="articleContentHtml" class="entry-content"></div>
<!-- 最后更新时间 -->
<div class="article-update-time">
<span>文章最后更新于 {{ article.updateTime }}</span>
</div>
<!-- 分类 -->
<div class="article-sort">
<span @click="$router.push({path: '/sort', query: {sortId: article.sortId, labelId: article.labelId}})">{{ article.sort.sortName +" ▶ "+ article.label.labelName}}</span>
</div>
<!-- 作者信息 -->
<blockquote>
<div>
作者{{article.username}}
</div> </div>
<div> <!-- 分类 -->
版权声明转载请注明文章出处 <div class="article-sort">
<span @click="$router.push({path: '/sort', query: {sortId: article.sortId, labelId: article.labelId}})">{{ article.sort.sortName +" ▶ "+ article.label.labelName}}</span>
</div>
<!-- 作者信息 -->
<blockquote>
<div>
作者{{article.username}}
</div>
<div>
版权声明转载请注明文章出处
</div>
</blockquote>
<!-- 订阅 -->
<div class="myCenter" id="article-like" @click="subscribeLabel()">
<i class="el-icon-thumb article-like-icon" :class="{'article-like': subscribe}"></i>
</div> </div>
</blockquote>
<!-- 点赞 -->
<div class="myCenter" id="article-like">
<i class="el-icon-thumb article-like-icon" :class="{'article-like': article.likeCount}"></i>
</div>
<!-- 评论 --> <!-- 评论 -->
<div v-if="article.commentStatus === true"> <div v-if="article.commentStatus === true">
<comment :type="'article'" :source="article.id" :userId="article.userId"></comment> <comment :type="'article'" :source="article.id" :userId="article.userId"></comment>
</div>
</div> </div>
<div id="toc" class="toc"></div>
</div> </div>
<div id="toc" class="toc"></div> <div style="background: var(--background)">
</div> <myFooter></myFooter>
</div>
<div style="background: var(--background)"> <el-dialog title="最新进展"
<myFooter></myFooter> :visible.sync="weiYanDialogVisible"
width="40%"
:append-to-body="true"
destroy-on-close
center>
<div>
<div class="myCenter" style="margin-bottom: 20px">
<el-date-picker
v-model="newsTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
align="center"
placeholder="选择日期时间">
</el-date-picker>
</div>
<commentBox :disableGraffiti="true"
@submitComment="submitWeiYan">
</commentBox>
</div>
</el-dialog>
</div> </div>
<el-dialog title="最新进展" <!-- 微信 -->
:visible.sync="weiYanDialogVisible" <el-dialog title="密码"
width="40%" :modal="false"
:visible.sync="showPasswordDialog"
width="25%"
:append-to-body="true" :append-to-body="true"
destroy-on-close destroy-on-close
center> center>
<div> <div>
<div class="myCenter" style="margin-bottom: 20px"> <div>
<el-date-picker <div class="password-content">{{tips}}</div>
v-model="newsTime" </div>
value-format="yyyy-MM-dd HH:mm:ss" <div style="margin: 20px auto">
type="datetime" <el-input maxlength="30" v-model="password"></el-input>
align="center" </div>
placeholder="选择日期时间"> <div style="display: flex;justify-content: center">
</el-date-picker> <proButton :info="'提交'"
@click.native="submitPassword()"
:before="$constant.before_color_2"
:after="$constant.after_color_2">
</proButton>
</div> </div>
<commentBox :disableGraffiti="true"
@submitComment="submitWeiYan">
</commentBox>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
@ -192,6 +219,7 @@
const comment = () => import( "./comment/comment"); const comment = () => import( "./comment/comment");
const process = () => import( "./common/process"); const process = () => import( "./common/process");
const commentBox = () => import( "./comment/commentBox"); const commentBox = () => import( "./comment/commentBox");
const proButton = () => import( "./common/proButton");
import MarkdownIt from 'markdown-it'; import MarkdownIt from 'markdown-it';
export default { export default {
@ -199,26 +227,91 @@
myFooter, myFooter,
comment, comment,
commentBox, commentBox,
proButton,
process process
}, },
data() { data() {
return { return {
id: this.$route.query.id, id: this.$route.query.id,
subscribe: false,
article: {}, article: {},
articleContentHtml: "", articleContentHtml: "",
treeHoleList: [], treeHoleList: [],
weiYanDialogVisible: false, weiYanDialogVisible: false,
newsTime: "" newsTime: "",
showPasswordDialog: false,
password: "",
tips: ""
}; };
}, },
created() { created() {
this.getArticle(); if (!this.$common.isEmpty(this.id)) {
this.getArticle(localStorage.getItem("article_password_" + this.id));
if ("0" !== localStorage.getItem("showSubscribe")) {
this.$notify({
title: '文章订阅',
type: 'success',
message: '点击文章下方小手 - 订阅/取消订阅专栏(标签)',
duration: 0,
onClose: () => localStorage.setItem("showSubscribe", "0")
});
}
}
}, },
mounted() { mounted() {
// window.addEventListener("scroll", this.onScrollPage); // window.addEventListener("scroll", this.onScrollPage);
}, },
methods: { methods: {
subscribeLabel() {
if (this.$common.isEmpty(this.$store.state.currentUser)) {
this.$message({
message: "请先登录!",
type: "error"
});
return;
}
this.$confirm('确认' + (this.subscribe ? '取消订阅' : '订阅') + '专栏【' + this.article.label.labelName + '】?' + (this.subscribe ? "" : "订阅专栏后,该专栏发布新文章将通过邮件通知订阅用户。"), this.subscribe ? "取消订阅" : "文章订阅", {
confirmButtonText: '确定',
cancelButtonText: '取消',
center: true
}).then(() => {
this.$http.get(this.$constant.baseURL + "/user/subscribe", {
labelId: this.article.labelId,
flag: !this.subscribe
})
.then((res) => {
if (!this.$common.isEmpty(res.data)) {
this.$store.commit("loadCurrentUser", res.data);
}
this.subscribe = !this.subscribe;
})
.catch((error) => {
this.$message({
message: error.message,
type: "error"
});
});
}).catch(() => {
this.$message({
type: 'success',
message: '已取消!'
});
});
},
submitPassword() {
if (this.$common.isEmpty(this.password)) {
this.$message({
message: "请先输入密码!",
type: "error"
});
return;
}
this.getArticle(this.password);
},
deleteTreeHole(id) { deleteTreeHole(id) {
if (this.$common.isEmpty(this.$store.state.currentUser)) { if (this.$common.isEmpty(this.$store.state.currentUser)) {
this.$message({ this.$message({
@ -334,8 +427,8 @@
let headings = $(".entry-content").find("h1, h2, h3, h4, h5, h6"); let headings = $(".entry-content").find("h1, h2, h3, h4, h5, h6");
headings.attr('id', (i, id) => id || 'toc-' + i); headings.attr('id', (i, id) => id || 'toc-' + i);
}, },
getArticle() { getArticle(password) {
this.$http.get(this.$constant.baseURL + "/article/getArticleById", {id: this.id, flag: true}) this.$http.get(this.$constant.baseURL + "/article/getArticleById", {id: this.id, password: password})
.then((res) => { .then((res) => {
if (!this.$common.isEmpty(res.data)) { if (!this.$common.isEmpty(res.data)) {
this.article = res.data; this.article = res.data;
@ -348,13 +441,31 @@
// todo toc // todo toc
// this.getTocbot(); // this.getTocbot();
}); });
if (!this.$common.isEmpty(password)) {
localStorage.setItem("article_password_" + this.id, password);
}
this.showPasswordDialog = false;
if (!this.$common.isEmpty(this.$store.state.currentUser) && !this.$common.isEmpty(this.$store.state.currentUser.subscribe)) {
this.subscribe = JSON.parse(this.$store.state.currentUser.subscribe).includes(this.article.labelId);
}
} }
}) })
.catch((error) => { .catch((error) => {
this.$message({ if ("密码错误" === error.message.substr(0, 4)) {
message: error.message, if (!this.$common.isEmpty(password)) {
type: "error" this.$message({
}); message: "密码错误,请重新输入!",
type: "error"
});
}
this.tips = error.message.substr(4);
this.showPasswordDialog = true;
} else {
this.$message({
message: error.message,
type: "error"
});
}
}); });
}, },
highlight() { highlight() {
@ -583,6 +694,12 @@
border-bottom: unset; border-bottom: unset;
} }
.password-content {
font-size: 13px;
color: var(--maxGreyFont);
line-height: 1.5;
}
@media screen and (max-width: 700px) { @media screen and (max-width: 700px) {
.article-info-container { .article-info-container {
left: 20px; left: 20px;

@ -266,11 +266,41 @@
} }
let obj = new Blob([u8arr], {type: mine}); let obj = new Blob([u8arr], {type: mine});
let key = "graffiti" + "/" + this.$store.state.currentUser.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentUser.id + new Date().getTime() + Math.floor(Math.random() * 1000) + ".png"; let key = "graffiti" + "/" + this.$store.state.currentUser.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentUser.id + new Date().getTime() + Math.floor(Math.random() * 1000) + ".png";
let storeType = localStorage.getItem("defaultStoreType");
let fd = new FormData(); let fd = new FormData();
fd.append("file", obj); fd.append("file", obj);
fd.append("key", key); fd.append("key", key);
fd.append("relativePath", key);
fd.append("type", "graffiti");
fd.append("storeType", storeType);
this.$http.get(this.$constant.baseURL + "/qiniu/getUpToken", {key: key}) if (storeType === "local") {
this.saveLocal(fd);
} else if (storeType === "qiniu") {
this.saveQiniu(fd);
}
},
saveLocal(fd) {
this.$http.upload(this.$constant.baseURL + "/resource/upload", fd)
.then((res) => {
if (!this.$common.isEmpty(res.data)) {
this.clearContext();
let url = res.data;
let img = "<你画我猜," + url + ">";
this.$emit("addGraffitiComment", img);
}
})
.catch((error) => {
this.$message({
message: error.message,
type: "error"
});
});
},
saveQiniu(fd) {
this.$http.get(this.$constant.baseURL + "/qiniu/getUpToken", {key: fd.get("key")})
.then((res) => { .then((res) => {
if (!this.$common.isEmpty(res.data)) { if (!this.$common.isEmpty(res.data)) {
fd.append("token", res.data); fd.append("token", res.data);
@ -280,7 +310,8 @@
if (!this.$common.isEmpty(res.key)) { if (!this.$common.isEmpty(res.key)) {
this.clearContext(); this.clearContext();
let url = this.$constant.qiniuDownload + res.key; let url = this.$constant.qiniuDownload + res.key;
this.$common.saveResource(this, "graffiti", url, obj.size, obj.type); let file = fd.get("file");
this.$common.saveResource(this, "graffiti", url, file.size, file.type, "qiniu");
let img = "<你画我猜," + url + ">"; let img = "<你画我猜," + url + ">";
this.$emit("addGraffitiComment", img); this.$emit("addGraffitiComment", img);
} }

@ -65,6 +65,10 @@
type: String, type: String,
default: "picture" default: "picture"
}, },
storeType: {
type: String,
default: localStorage.getItem("defaultStoreType")
},
accept: { accept: {
type: String, type: String,
default: "image/*" default: "image/*"
@ -107,37 +111,53 @@
let key = this.prefix + "/" + (!this.$common.isEmpty(this.$store.state.currentUser.username) ? (this.$store.state.currentUser.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentUser.id) : (this.$store.state.currentAdmin.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentAdmin.id)) + new Date().getTime() + Math.floor(Math.random() * 1000) + suffix; let key = this.prefix + "/" + (!this.$common.isEmpty(this.$store.state.currentUser.username) ? (this.$store.state.currentUser.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentUser.id) : (this.$store.state.currentAdmin.username.replace(/[^a-zA-Z]/g, '') + this.$store.state.currentAdmin.id)) + new Date().getTime() + Math.floor(Math.random() * 1000) + suffix;
const xhr = new XMLHttpRequest(); if (this.storeType === "local") {
xhr.open('get', this.$constant.baseURL + "/qiniu/getUpToken?key=" + key, false); let fd = new FormData();
if (this.isAdmin) { fd.append("file", options.file);
xhr.setRequestHeader("Authorization", localStorage.getItem("adminToken")); fd.append("key", key);
} else { fd.append("relativePath", key);
xhr.setRequestHeader("Authorization", localStorage.getItem("userToken")); fd.append("type", this.prefix);
} fd.append("storeType", this.storeType);
try { return this.$http.upload(this.$constant.baseURL + "/resource/upload", fd, this.isAdmin);
xhr.send(); } else if (this.storeType === "qiniu") {
const res = JSON.parse(xhr.responseText); const xhr = new XMLHttpRequest();
if (res !== null && res.hasOwnProperty("code") && res.code === 200) { xhr.open('get', this.$constant.baseURL + "/qiniu/getUpToken?key=" + key, false);
options.data = { if (this.isAdmin) {
token: res.data, xhr.setRequestHeader("Authorization", localStorage.getItem("adminToken"));
key: key
};
return upload(options);
} else if (res !== null && res.hasOwnProperty("code") && res.code !== 200) {
return Promise.reject(res.message);
} else { } else {
return Promise.reject("服务异常!"); xhr.setRequestHeader("Authorization", localStorage.getItem("userToken"));
}
try {
xhr.send();
const res = JSON.parse(xhr.responseText);
if (res !== null && res.hasOwnProperty("code") && res.code === 200) {
options.data = {
token: res.data,
key: key
};
return upload(options);
} else if (res !== null && res.hasOwnProperty("code") && res.code !== 200) {
return Promise.reject(res.message);
} else {
return Promise.reject("服务异常!");
}
} catch (e) {
return Promise.reject(e.message);
} }
} catch (e) {
return Promise.reject(e.message);
} }
}, },
// //
handleSuccess(response, file, fileList) { handleSuccess(response, file, fileList) {
let url = this.$constant.qiniuDownload + response.key; let url;
this.$common.saveResource(this, this.prefix, url, file.size, file.raw.type, this.isAdmin); if (this.storeType === "local") {
url = response.data;
} else if (this.storeType === "qiniu") {
url = this.$constant.qiniuDownload + response.key;
this.$common.saveResource(this, this.prefix, url, file.size, file.raw.type, "qiniu", this.isAdmin);
}
this.$emit("addPicture", url); this.$emit("addPicture", url);
}, },
handleError(err, file, fileList) { handleError(err, file, fileList) {

@ -67,10 +67,34 @@
<img class="after-img" :src="$constant.friendLetterBottom" style="width: 100%"/> <img class="after-img" :src="$constant.friendLetterBottom" style="width: 100%"/>
</div> </div>
<div style="font-size: 20px;font-weight: bold;margin-top: 40px">🌸本站信息</div>
<div>
<blockquote>
<div>网站名称: $$$$POETIZE</div>
<div>网址: $$$$https://poetize.cn</div>
<div>头像: $$$$https://s1.ax1x.com/2022/11/10/z9E7X4.jpg</div>
<div>描述: $$$$这是一个 Vue2 Vue3 SpringBoot 结合的产物</div>
<div>网站封面: $$$$https://s1.ax1x.com/2022/11/10/z9VlHs.png</div>
</blockquote>
</div>
<div style="font-size: 20px;font-weight: bold">🌸申请方式</div>
<div>
<blockquote>
<div>点击上方信封</div>
<div>不会添加带有广告营销和没有实质性内容的友链🚫🚫🚫</div>
<div>申请之前请将本网站添加为您的友链哦🎟🎟🎟</div>
</blockquote>
</div>
<hr>
<h2 style="margin-top: 60px">青出于蓝</h2>
<card :resourcePathList="friendList['♥️青出于蓝']" @clickResourcePath="clickFriend"></card>
<hr> <hr>
<h2>🥇友情链接</h2> <h2 style="margin-top: 60px">🥇友情链接</h2>
<card :resourcePathList="friendList" @clickResourcePath="clickFriend"></card> <card :resourcePathList="friendList['🥇友情链接']" @clickResourcePath="clickFriend"></card>
</div> </div>
</div> </div>
@ -93,13 +117,7 @@
data() { data() {
return { return {
pagination: { friendList: {},
current: 1,
size: 9999,
desc: false,
resourceType: "friendUrl"
},
friendList: [],
friend: { friend: {
title: "", title: "",
introduction: "", introduction: "",
@ -189,10 +207,10 @@
window.open(path); window.open(path);
}, },
getFriends() { getFriends() {
this.$http.post(this.$constant.baseURL + "/webInfo/listResourcePath", this.pagination) this.$http.get(this.$constant.baseURL + "/webInfo/listFriend")
.then((res) => { .then((res) => {
if (!this.$common.isEmpty(res.data)) { if (!this.$common.isEmpty(res.data)) {
this.friendList = res.data.records; this.friendList = res.data;
} }
}) })
.catch((error) => { .catch((error) => {
@ -342,6 +360,16 @@
padding: 20px 0; padding: 20px 0;
} }
blockquote {
line-height: 2;
border-left: 0.2rem solid #ed6ea0;
padding: 10px 1rem;
background-color: #ffe6fa;
border-radius: 4px;
margin: 20px auto;
color: var(--maxGreyFont);
}
@media screen and (max-width: 700px) { @media screen and (max-width: 700px) {
.form-wrap { .form-wrap {
width: auto; width: auto;

@ -371,7 +371,7 @@
}); });
} else { } else {
let userToken = this.$common.encrypt(localStorage.getItem("userToken")); let userToken = this.$common.encrypt(localStorage.getItem("userToken"));
window.open(this.$constant.imBaseURL + "?userToken=" + userToken); window.open(this.$constant.imBaseURL + "?userToken=" + userToken + "&defaultStoreType=" + localStorage.getItem("defaultStoreType"));
} }
}, },
logout() { logout() {
@ -393,6 +393,7 @@
.then((res) => { .then((res) => {
if (!this.$common.isEmpty(res.data)) { if (!this.$common.isEmpty(res.data)) {
this.$store.commit("loadWebInfo", res.data); this.$store.commit("loadWebInfo", res.data);
localStorage.setItem("defaultStoreType", res.data.defaultStoreType);
} }
}) })
.catch((error) => { .catch((error) => {

@ -24,7 +24,7 @@
</div> </div>
<!-- 搜索 --> <!-- 搜索 -->
<div style="padding: 15px;border-radius: 10px;margin-top: 40px;animation: hideToShow 1s ease-in-out" <div style="padding: 15px;border-radius: 10px;margin-top: 30px;animation: hideToShow 1s ease-in-out"
class="shadow-box background-opacity wow"> class="shadow-box background-opacity wow">
<div style="color: var(--lightGreen);font-size: 20px;font-weight: bold;margin-bottom: 10px"> <div style="color: var(--lightGreen);font-size: 20px;font-weight: bold;margin-bottom: 10px">
搜索 搜索
@ -48,7 +48,7 @@
<!-- 推荐文章 --> <!-- 推荐文章 -->
<div v-if="!$common.isEmpty(recommendArticles)" <div v-if="!$common.isEmpty(recommendArticles)"
style="padding: 25px;border-radius: 10px;margin-top: 40px;animation: hideToShow 1s ease-in-out" style="padding: 25px;border-radius: 10px;margin-top: 30px;animation: hideToShow 1s ease-in-out"
class="shadow-box background-opacity wow"> class="shadow-box background-opacity wow">
<div class="card-content2-title"> <div class="card-content2-title">
<i class="el-icon-reading card-content2-icon"></i> <i class="el-icon-reading card-content2-icon"></i>
@ -77,39 +77,13 @@
</div> </div>
</div> </div>
<!-- 赞赏 -->
<div class="shadow-box-mini background-opacity wow admire-box"
v-if="!$common.isEmpty(admires)">
<div style="font-weight: bold;margin-bottom: 20px">🧨赞赏名单</div>
<div>
<vue-seamless-scroll :data="admires" style="height: 200px;overflow: hidden">
<div v-for="(item, i) in admires"
style="display: flex;justify-content: space-between"
:key="i">
<div style="display: flex">
<el-avatar style="margin-bottom: 10px" :size="36" :src="item.avatar"></el-avatar>
<div style="margin-left: 10px;height: 36px;line-height: 36px;overflow: hidden;max-width: 80px">
{{ item.username }}
</div>
</div>
<div style="height: 36px;line-height: 36px">
{{ item.admire }}
</div>
</div>
</vue-seamless-scroll>
</div>
<div class="admire-btn" @click="showAdmire()">
赞赏
</div>
</div>
<!-- 速览 --> <!-- 速览 -->
<div v-for="(sort, index) in sortInfo" <div v-for="(sort, index) in sortInfo"
@click="selectSort(sort)" @click="selectSort(sort)"
:key="index" :key="index"
:style="{background: $constant.sortColor[index % $constant.sortColor.length]}" :style="{background: $constant.sortColor[index % $constant.sortColor.length]}"
class="shadow-box-mini background-opacity wow" class="shadow-box-mini background-opacity wow"
style="position: relative;padding: 20px 25px 40px;border-radius: 10px;animation: hideToShow 1s ease-in-out;margin-top: 40px;cursor: pointer;color: var(--white)"> style="position: relative;padding: 10px 25px 15px;border-radius: 10px;animation: hideToShow 1s ease-in-out;margin-top: 30px;cursor: pointer;color: var(--white)">
<div>速览</div> <div>速览</div>
<div class="sort-name"> <div class="sort-name">
{{sort.sortName}} {{sort.sortName}}
@ -121,7 +95,7 @@
<!-- 分类 --> <!-- 分类 -->
<div class="shadow-box background-opacity wow" <div class="shadow-box background-opacity wow"
style="margin-top: 40px;padding: 25px 25px 5px;border-radius: 10px;animation: hideToShow 1s ease-in-out"> style="margin-top: 30px;padding: 25px 25px 5px;border-radius: 10px;animation: hideToShow 1s ease-in-out">
<div class="card-content2-title"> <div class="card-content2-title">
<i class="el-icon-folder-opened card-content2-icon"></i> <i class="el-icon-folder-opened card-content2-icon"></i>
<span>分类</span> <span>分类</span>
@ -136,6 +110,32 @@
</div> </div>
</div> </div>
<!-- 赞赏 -->
<div class="shadow-box-mini background-opacity wow admire-box"
v-if="!$common.isEmpty(admires)">
<div style="font-weight: bold;margin-bottom: 20px">🧨赞赏名单</div>
<div>
<vue-seamless-scroll :data="admires" style="height: 200px;overflow: hidden">
<div v-for="(item, i) in admires"
style="display: flex;justify-content: space-between"
:key="i">
<div style="display: flex">
<el-avatar style="margin-bottom: 10px" :size="36" :src="item.avatar"></el-avatar>
<div style="margin-left: 10px;height: 36px;line-height: 36px;overflow: hidden;max-width: 80px">
{{ item.username }}
</div>
</div>
<div style="height: 36px;line-height: 36px">
{{ item.admire }}
</div>
</div>
</vue-seamless-scroll>
</div>
<div class="admire-btn" @click="showAdmire()">
赞赏
</div>
</div>
<!-- 微信 --> <!-- 微信 -->
<el-dialog title="赞赏" <el-dialog title="赞赏"
:visible.sync="showAdmireDialog" :visible.sync="showAdmireDialog"
@ -380,14 +380,14 @@
.sort-name { .sort-name {
font-weight: bold; font-weight: bold;
font-size: 25px; font-size: 25px;
margin-top: 30px; margin-top: 15px;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
} }
.sort-name:after { .sort-name:after {
top: 98px; top: 74px;
width: 22px; width: 22px;
left: 26px; left: 26px;
height: 2px; height: 2px;
@ -402,7 +402,7 @@
padding: 25px; padding: 25px;
border-radius: 10px; border-radius: 10px;
animation: hideToShow 1s ease-in-out; animation: hideToShow 1s ease-in-out;
margin-top: 40px; margin-top: 30px;
} }
.admire-btn { .admire-btn {

@ -140,12 +140,13 @@ export default {
/** /**
* 保存资源 * 保存资源
*/ */
saveResource(that, type, path, size, mimeType, isAdmin = false) { saveResource(that, type, path, size, mimeType, storeType, isAdmin = false) {
let resource = { let resource = {
type: type, type: type,
path: path, path: path,
size: size, size: size,
mimeType: mimeType mimeType: mimeType,
storeType: storeType
}; };
that.$http.post(that.$constant.baseURL + "/resource/saveResource", resource, isAdmin) that.$http.post(that.$constant.baseURL + "/resource/saveResource", resource, isAdmin)

@ -90,11 +90,13 @@ export default {
let config; let config;
if (isAdmin) { if (isAdmin) {
config = { config = {
headers: {"Authorization": localStorage.getItem("adminToken"), "Content-Type": "multipart/form-data"} headers: {"Authorization": localStorage.getItem("adminToken"), "Content-Type": "multipart/form-data"},
timeout: 60000
}; };
} else { } else {
config = { config = {
headers: {"Authorization": localStorage.getItem("userToken"), "Content-Type": "multipart/form-data"} headers: {"Authorization": localStorage.getItem("userToken"), "Content-Type": "multipart/form-data"},
timeout: 60000
}; };
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

Loading…
Cancel
Save