This commit is contained in:
Jesse-Ma
2022-12-01 16:36:26 +08:00
parent 332f556d1d
commit b2efddc755
16 changed files with 190 additions and 104 deletions

0
.env Normal file
View File

4
.env.development Normal file
View File

@@ -0,0 +1,4 @@
NODE_ENV = developement
VUE_APP_BASE_NAME = developement
VUE_APP_BASE_URL = http://localhost:8080

3
.env.production Normal file
View File

@@ -0,0 +1,3 @@
NODE_ENV = production
VUE_APP_BASE_NAME = production
VUE_APP_BASE_URL = https://flagnote.com

View File

@@ -4,7 +4,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build --mode production",
"build.test": "vue-cli-service build --mode test", "build.test": "vue-cli-service build --mode test",
"build.production": "vue-cli-service build --mode production", "build.production": "vue-cli-service build --mode production",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"

View File

@@ -4,10 +4,11 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="renderer" content="webkit" /> <meta name="renderer" content="webkit" />
<meta name="force-rendering" content="webkit"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta <meta
name="viewport" name="viewport"
content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=2.0, user-scalable=no" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=2.0, user-scalable=yes"
/> />
<meta name="keywords" content="flagnote" /> <meta name="keywords" content="flagnote" />
@@ -16,6 +17,8 @@
<meta name="theme-color" content="#ed4014" /> <meta name="theme-color" content="#ed4014" />
<meta name="format-detection" content="telephone=no,email=no,adress=no" /> <meta name="format-detection" content="telephone=no,email=no,adress=no" />
<meta name="google" content="notranslate">
<meta http-equiv="Expires" content="0" /> <meta http-equiv="Expires" content="0" />
<meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-control" content="no-cache" /> <meta http-equiv="Cache-control" content="no-cache" />

View File

@@ -114,8 +114,8 @@ body {
} }
button span { button span {
font-size: 16px !important; font-size: 15px !important;
font-family: apple-system,BlinkMacSystemFont,Helvetica Neue,PingFang SC,Microsoft YaHei,Source Han Sans SC,Noto Sans CJK SC,WenQuanYi Micro Hei,sans-serif; font-family: apple-system,BlinkMacSystemFont,Helvetica Neue,PingFang SC,Microsoft YaHei,Source Han Sans SC,Noto Sans CJK SC,WenQuanYi Micro Hei,sans-serif;
margin-bottom: 5px; margin-bottom: 6px;
} }
</style> </style>

View File

@@ -3,8 +3,7 @@ import { getStoreKey } from "@/api/lock";
import storage from "@/libs/storage"; import storage from "@/libs/storage";
import { md5 } from "@/libs/secret"; import { md5 } from "@/libs/secret";
const servicePath = "https://flagnote.com"; const servicePath = process.env.VUE_APP_BASE_URL;
//const servicePath = "http://localhost:8080";
export function saveNote(noteForm, secret) { export function saveNote(noteForm, secret) {
let storeKey = secret.storeKey; let storeKey = secret.storeKey;

View File

@@ -12,7 +12,16 @@ const en = {
selectAll: "Select All", selectAll: "Select All",
copy: "Copy", copy: "Copy",
copyAll: "Copy All", copyAll: "Copy All",
share: "Share" share: "Share",
close: "Close"
}, },
error: {
"100001": "Unknown Error!",
"100002": "Wrong Address",
"100003": "Deleted",
"100004": "Expired!",
"100005": "Not Available!",
"100006": "100006",
}
}; };
export default en; export default en;

View File

@@ -12,7 +12,16 @@ const zh = {
selectAll: "全选", selectAll: "全选",
copy: "复制", copy: "复制",
copyAll: "复制全部", copyAll: "复制全部",
share: "分享" share: "分享",
close: "关闭"
}, },
error: {
"100001": "未知错误!",
"100002": "地址有误!",
"100003": "内容已删除!",
"100004": "内容已过期!",
"100005": "内容不存在!",
"100006": "100006",
}
}; };
export default zh; export default zh;

View File

@@ -6,7 +6,7 @@ import VueAxios from 'vue-axios'
import './plugins/iview.js' import './plugins/iview.js'
import i18n from './i18n/' import i18n from './i18n/'
axios.defaults.baseURL="https://flagnote.com"; axios.defaults.baseURL= process.env.VUE_APP_BASE_URL;
Vue.use(VueAxios, axios) Vue.use(VueAxios, axios)

View File

@@ -2,8 +2,7 @@ import Vue from "vue";
import VueRouter from "vue-router"; import VueRouter from "vue-router";
import EditNote from "@/views/EditNote.vue"; import EditNote from "@/views/EditNote.vue";
import ViewNote from "@/views/ViewNote.vue"; import ViewNote from "@/views/ViewNote.vue";
import ErrorView from "@/views/ErrorView.vue"; import InvalidateNote from "@/views/InvalidateNote.vue";
import BlankNote from "@/views/BlankNote.vue";
import { getKeyMeta, getNoteMeta } from "@/api/note"; import { getKeyMeta, getNoteMeta } from "@/api/note";
import { getStoreKey } from "@/api/lock"; import { getStoreKey } from "@/api/lock";
import storage from "@/libs/storage"; import storage from "@/libs/storage";
@@ -12,6 +11,7 @@ Vue.use(VueRouter);
var keyMeta = null; var keyMeta = null;
var noteMeta = null; var noteMeta = null;
var errorMeta = null;
function getKeyMetaParam() { function getKeyMetaParam() {
return keyMeta; return keyMeta;
@@ -21,6 +21,10 @@ function getNoteMetaParam() {
return noteMeta; return noteMeta;
} }
function getErrorMetaParam() {
return errorMeta;
}
function getNoteView() { function getNoteView() {
let path = location.pathname; let path = location.pathname;
let key = path.substring(1, path.length); let key = path.substring(1, path.length);
@@ -31,7 +35,8 @@ function getNoteView() {
let regKey = /^[abcdefhikmnopqstuvwxyz23456789]{16}$/; let regKey = /^[abcdefhikmnopqstuvwxyz23456789]{16}$/;
if (!regKey.test(key)) { if (!regKey.test(key)) {
return; errorMeta = 100002;
return InvalidateNote;
} }
if (keyMeta && keyMeta.key) { if (keyMeta && keyMeta.key) {
@@ -42,29 +47,52 @@ function getNoteView() {
//set noteMeta //set noteMeta
noteMeta = getNoteMeta(key); noteMeta = getNoteMeta(key);
//invalidated key
if (!noteMeta || !noteMeta.key) { if (!noteMeta || !noteMeta.key) {
errorMeta = 100002;
return InvalidateNote;
}
let storeKey = getStoreKey(key); //validated state
if (1 == noteMeta.state) {
let storeInfo = storage.local.getText(storeKey);
if (storeInfo) {
let starray = storeInfo.split("|");
let commitFlag = starray[2];
if (commitFlag == "1") {
//timeout and clear local
storage.local.delete(storeKey );
return BlankNote;
} else {
//secondEdit
return EditNote;
}
} else {
//uncommited or timeout
return BlankNote;
}
}
// view in time
return ViewNote; return ViewNote;
}
//deleted
if (0 == noteMeta.state) {
let storeKey = getStoreKey(key);
storage.local.delete(storeKey);
// user deleted
if (noteMeta.ttl > 0) {
errorMeta = 100003;
return InvalidateNote;
} else {// timeout
errorMeta = 100004;
return InvalidateNote;
}
}
if (null == noteMeta.state) {
let storeKey = getStoreKey(key);
//if has storage , then edit
if (storage.local.getText(storeKey)) {
return EditNote;
} else {
//storage is empty
let df = storage.session.getText(storeKey + "_delete")
if (df) {//unsubmitted,user deleted.
errorMeta = 100003;
return InvalidateNote;
} else {//unsubmitted
errorMeta = 100005;
return InvalidateNote;
}
}
}
// other exception
errorMeta = 100001;
return InvalidateNote;
} }
function getHomeRedirect() { function getHomeRedirect() {
@@ -85,15 +113,10 @@ const routes = [
redirect: getHomeRedirect(), redirect: getHomeRedirect(),
}, },
{ {
path: "/error", path: "/:name([a-z0-9]{16})",
name: "error",
component: ErrorView,
},
{
path: "/:name([abcdefhikmnopqstuvwxyz23456789]{16})",
name: "note", name: "note",
component: getNoteView(), component: getNoteView(),
meta: { keyMeta: getKeyMetaParam(), noteMeta: getNoteMetaParam() }, meta: { keyMeta: getKeyMetaParam(), noteMeta: getNoteMetaParam(), errorMeta: getErrorMetaParam() },
//alias:'/xxxx' //alias:'/xxxx'
}, },
]; ];

View File

@@ -100,7 +100,7 @@
<Button-group size="large"> <Button-group size="large">
<Button aria-label="publish" type="error" :loading="model.submitting" <Button aria-label="publish" type="error" :loading="model.submitting"
style="margin-left:5px; border-radius: 0px;font-size: 23px;" @click="submitNote()" style="margin-left:5px; border-radius: 0px;font-size: 19px;" @click="submitNote()"
icon="md-cloud-upload">{{$t("button.share")}}</Button> icon="md-cloud-upload">{{$t("button.share")}}</Button>
<Button aria-label="menu" type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;" <Button aria-label="menu" type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;"
@click="switchMenu()" @blur.native="hideMenu()" icon="md-menu"></Button> @click="switchMenu()" @blur.native="hideMenu()" icon="md-menu"></Button>
@@ -163,12 +163,12 @@
<Footer class="layout-footer-center">2022 &copy; flagnote.com</Footer> <Footer class="layout-footer-center">2022 &copy; flagnote.com</Footer>
</Layout> </Layout>
<Modal v-model="model.showDelete" width="330" footer-hide class-name="fnmodal" :styles="{ borderRadius: 0 }"> <Modal v-model="model.showDelete" width="360" footer-hide class-name="fnmodal" :styles="{ borderRadius: 0 }">
<p style="text-align: center;font-size:medium ;margin-bottom: 20px;"> <p style="text-align: center;font-size:medium ;margin-bottom: 20px;">
{{ $t("message.askTodelete") }} {{ $t("message.askTodelete") }}
</p> </p>
<p style="text-align: center;"> <p style="text-align: center;">
<Button type="error" :loading="model.deleting" style="border-radius: 0px;" @click="dropNote()">{{ <Button type="error" :loading="model.deleting" style="border-radius: 0px;font-size: 19px;" @click="dropNote()">{{
$t("button.yes") $t("button.yes")
}}</Button> }}</Button>
</p> </p>
@@ -423,6 +423,7 @@ export default {
let storeInfo = storage.local.getText(that.secret.storeKey); let storeInfo = storage.local.getText(that.secret.storeKey);
let starray = storeInfo.split("|"); let starray = storeInfo.split("|");
storage.local.setText(that.secret.storeKey, starray[0] + '|' + starray[1] + '|1|' + starray[3] + '|' + starray[4]); storage.local.setText(that.secret.storeKey, starray[0] + '|' + starray[1] + '|1|' + starray[3] + '|' + starray[4]);
storage.session.setText(that.secret.storeKey+"_share",'1');
location.reload(); location.reload();
this.state.locking = 0; this.state.locking = 0;
} }
@@ -440,6 +441,7 @@ export default {
dropNote() { dropNote() {
this.model.deleting = true; this.model.deleting = true;
storage.local.delete(this.secret.storeKey); storage.local.delete(this.secret.storeKey);
storage.session.setText(this.secret.storeKey+"_delete",1);
location.reload(); location.reload();
}, },
bindToTopEvent() { bindToTopEvent() {

View File

@@ -1,17 +0,0 @@
<template>
<div class="home">
error
</div>
</template>
<script>
export default {
name: 'ErrorView',
components: {},
data() {
return {}
},
created() {
}
}
</script>

View File

@@ -37,6 +37,7 @@
</style> </style>
<style> <style>
</style> </style>
<template> <template>
<div class="layout" onkeydown="keydown"> <div class="layout" onkeydown="keydown">
@@ -85,6 +86,7 @@
<div id="noteText" style="text-align: center;min-height: 650px;" class="monoFt"> <div id="noteText" style="text-align: center;min-height: 650px;" class="monoFt">
<h1></h1> <h1></h1>
{{ $t("content.blankTip") }} {{ $t("content.blankTip") }}
{{ $t("error."+this.errorInfo.code) }}
</div> </div>
</div> </div>
</Card> </Card>
@@ -126,10 +128,14 @@ export default {
lock: 0, lock: 0,
locking: 0, locking: 0,
commited: 0 commited: 0
},
errorInfo: {
code: 0
} }
} }
}, },
created() { created() {
this.errorInfo.code = this.$route.meta.errorMeta;
this.noteForm.key = this.$route.params.name; this.noteForm.key = this.$route.params.name;
}, },
mounted() { mounted() {

View File

@@ -68,6 +68,21 @@
</style> </style>
<style> <style>
#qrUrl {
color: #ed4014;
font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei";
}
#qrUrl::selection {
background-color: #ed4014;
color: #ffffff;
}
#copyBtn {
color: #ed4014;
font-size:large;
}
.ivu-btn-text:focus { .ivu-btn-text:focus {
margin-top: -3px; margin-top: -3px;
box-shadow: none !important; box-shadow: none !important;
@@ -168,7 +183,7 @@
<Button-group size="large"> <Button-group size="large">
<Button aria-label="share" type="error" <Button aria-label="share" type="error"
style="margin-left:5px; border-radius: 0px;font-size: 23px; font-family: Arial, sans-serif" style="margin-left:5px; border-radius: 0px;font-size: 19px; font-family: Arial, sans-serif"
@click="showShareModel()" icon="md-cloud-done">{{ state.ttlDesc }}</Button> @click="showShareModel()" icon="md-cloud-done">{{ state.ttlDesc }}</Button>
<Button aria-label="menu" type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;" <Button aria-label="menu" type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;"
@@ -236,23 +251,34 @@
</Layout> </Layout>
<Modal v-model="model.showShare" width="330" footer-hide class-name="qrmodal" :styles="{ borderRadius: 0 }"> <Modal v-model="model.showShare" width="360" footer-hide class-name="qrmodal" :styles="{ borderRadius: 0 }">
<p style="text-align: center;"> <p style="text-align: center;
<canvas id="qrimg" class=""></canvas> z-index: 1000;
position: absolute;
top: -2px;
left: 0px;
width: 100%;">
<Tag style="border-radius: 0px;" v-show="model.copyTip" color="#ed4014" text="">Url Copied.</Tag>
</p> </p>
<p style="text-align: center;"> <p style="text-align: center;margin-top:20px;line-height:100%">
<span id="tag-copy" class="noteUrl" :data-clipboard-text="noteForm.noteUrl" data-clipboard-action="copy">{{ <span style="margin-right:3px;" id="copyBtn"><Icon type="md-copy" /></span><span id="qrUrl">{{ noteForm.noteUrl }}</span>
noteForm.noteUrl </p>
}}</span>
<p style="text-align: center;margin-top:5px;">
<canvas id="qrImg" class=""></canvas>
</p>
<p style="text-align: center;margin-top:10px;">
<Button type="error" style="border-radius: 0px;font-size:19px;"
@click="closeShareModel()">{{$t("button.close")}}</Button>
</p> </p>
</Modal> </Modal>
<Modal v-model="model.showDelete" width="330" footer-hide class-name="fnmodal" :styles="{ borderRadius: 0 }"> <Modal v-model="model.showDelete" width="360" footer-hide class-name="fnmodal" :styles="{ borderRadius: 0 }">
<p style="text-align: center;font-size:medium;margin-bottom: 20px;"> <p style="text-align: center;font-size:medium;margin-bottom: 20px;">
{{ $t("message.askTodelete") }} {{ $t("message.askTodelete") }}
</p> </p>
<p style="text-align: center;"> <p style="text-align: center;">
<Button type="error" :loading="model.deleting" style="border-radius: 0px;" @click="dropNote()">{{ <Button type="error" :loading="model.deleting" style="border-radius: 0px;font-size:19px;" @click="dropNote()">{{
$t("button.yes") $t("button.yes")
}}</Button> }}</Button>
</p> </p>
@@ -308,6 +334,7 @@ export default {
showShare: false, showShare: false,
deleting: false, deleting: false,
showDownloadText: false, showDownloadText: false,
copyTip: false,
}, },
toTopState: false, toTopState: false,
showMenuState: false, showMenuState: false,
@@ -343,7 +370,6 @@ export default {
this.secret.cipher = "00000000000000000000000000000000";//noteMeta.cipher; //读者有没有值可配置 this.secret.cipher = "00000000000000000000000000000000";//noteMeta.cipher; //读者有没有值可配置
this.secret.md5 = noteMeta.md5; this.secret.md5 = noteMeta.md5;
this.startClock(); this.startClock();
storage.local.dynamicClear(); storage.local.dynamicClear();
@@ -360,7 +386,12 @@ export default {
}, },
mounted() { mounted() {
//this.bindCopyTextEvent();
let stateInfo = storage.session.getText(this.secret.storeKey + "_share");
if (stateInfo == '1') {
storage.session.setText(this.secret.storeKey + "_share", '0');
this.showShareModel();
}
const myObserver = new ResizeObserver(entries => { const myObserver = new ResizeObserver(entries => {
// iterate over the entries, do something. // iterate over the entries, do something.
@@ -437,7 +468,7 @@ export default {
}, },
showShareModel() { showShareModel() {
this.model.showShare = true; this.model.showShare = true;
let qrimg = document.getElementById("qrimg"); let qrimg = document.getElementById("qrImg");
let qrurl = "https://flagnote.com/" + this.noteForm.key; let qrurl = "https://flagnote.com/" + this.noteForm.key;
var opts = { var opts = {
errorCorrectionLevel: 'Q', errorCorrectionLevel: 'Q',
@@ -452,6 +483,12 @@ export default {
} }
} }
QRCode.toCanvas(qrimg, qrurl, opts) QRCode.toCanvas(qrimg, qrurl, opts)
storage.session.setText(this.secret.storeKey + "_share", '1');
},
closeShareModel() {
this.model.showShare = false;
storage.session.setText(this.secret.storeKey + "_share", '0');
}, },
showDeleteModel() { showDeleteModel() {
this.model.showDelete = true; this.model.showDelete = true;
@@ -537,9 +574,18 @@ export default {
}, },
bindCopyUrlEvent() { bindCopyUrlEvent() {
let that = this; let that = this;
var clipboard = new Clipboard("#tag-copy") var clipboard = new Clipboard("#copyBtn", {
target: function () {
return document.querySelector('#qrUrl');
}
})
clipboard.on('success', function () { clipboard.on('success', function () {
that.$Message.success({ content: 'url copied.' }); that.model.copyTip = true;
let tipTimer = setInterval(() => {
that.model.copyTip = false;
clearInterval(tipTimer);
}, 1500);
}); });
clipboard.on('error', function () { clipboard.on('error', function () {

View File

@@ -9,8 +9,7 @@ module.exports = defineConfig({
configureWebpack: (config) => { configureWebpack: (config) => {
// 为生产环境修改配置 // 为生产环境修改配置
//if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
config.plugins.push( config.plugins.push(
new WebpackObfuscator({ new WebpackObfuscator({
compact: true,//压缩代码 compact: true,//压缩代码
@@ -40,7 +39,7 @@ module.exports = defineConfig({
deleteOriginalAssets: false, // 是否删除未压缩的源文件谨慎设置如果希望提供非gzip的资源可不设置或者设置为false比如删除打包后的gz后还可以加载到原始资源文件 deleteOriginalAssets: false, // 是否删除未压缩的源文件谨慎设置如果希望提供非gzip的资源可不设置或者设置为false比如删除打包后的gz后还可以加载到原始资源文件
}), }),
) )
}
}, },
transpileDependencies: true, transpileDependencies: true,
chainWebpack: (config) => { chainWebpack: (config) => {
@@ -52,7 +51,7 @@ module.exports = defineConfig({
devServer: { devServer: {
proxy: { proxy: {
"/note": { "/note": {
target: "http://localhost:3333/", // 后台接口域名 target: "http://localhost:55555/", // 后台接口域名
secure: false, // 如果是https接口需要配置这个参数 secure: false, // 如果是https接口需要配置这个参数
changeOrigin: true, //是否跨域 changeOrigin: true, //是否跨域
pathRewrite: { pathRewrite: {