This commit is contained in:
Jesse-Ma
2022-07-21 18:51:30 +08:00
parent 0bdd2eea5c
commit deb1fbe49d
22 changed files with 26943 additions and 346 deletions

19846
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,16 +9,21 @@
}, },
"dependencies": { "dependencies": {
"axios": "^0.26.0", "axios": "^0.26.0",
"canvas-toBlob": "^1.0.0",
"clipboard": "^2.0.11",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pako": "^2.0.4", "pako": "^2.0.4",
"qrcode": "^1.5.0",
"view-design": "^4.0.0", "view-design": "^4.0.0",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-axios": "^3.4.1", "vue-axios": "^3.4.1",
"vue-i18n": "^8.27.2",
"vue-router": "^3.5.1" "vue-router": "^3.5.1"
}, },
"devDependencies": { "devDependencies": {
@@ -28,6 +33,7 @@
"@vue/cli-plugin-eslint": "~5.0.0", "@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-service": "~5.0.0", "@vue/cli-service": "~5.0.0",
"compression-webpack-plugin": "^10.0.0",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3", "eslint-plugin-vue": "^8.0.3",
"vue-cli-plugin-iview": "^2.0.0", "vue-cli-plugin-iview": "^2.0.0",

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="">
<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="/favicon.png" />
<title>flagnote.com</title>
<style>
body {
background-color: #dddddd
}
</style>
<script type="text/javascript">
</script>
</head>
<body>
<strong>IE is not supported.</strong>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,14 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang=""> <html lang="">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.png"> <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
<style> <style>
body { body {
background-color: #dddddd;
} }
</style> </style>
<!-- <!--
@@ -35,11 +35,51 @@
}; };
</script> </script>
--> -->
<script type="text/javascript">
(function () {
var ua = navigator.userAgent.toLocaleLowerCase();
var browserType = "",
browserVersion = "";
if (ua.match(/msie/) != null || ua.match(/trident/) != null) {
browserType = "IE";
alert("IE is not supported.");
window.location = "/IeIsNotSupported.html";
}
var lang = navigator.language;
if (lang) {
if (localStorage) {
if (!localStorage.getItem("locale")) {
localStorage.setItem("locale", lang);
}
}
}
})();
</script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=G-FPS9PD2DFF"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "G-FPS9PD2DFF");
</script>
</head> </head>
<body style="background-color: #dddddd;"> <body>
<noscript> <noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. <strong
Please enable it to continue.</strong> >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript> </noscript>
<div id="app"></div> <div id="app"></div>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->

2
public/robots.txt Normal file
View File

@@ -0,0 +1,2 @@
User-agent: *
Disallow: /

View File

@@ -36,4 +36,77 @@ body {
background: red !important; background: red !important;
} }
.showBlock{
display: block;
}
.hideBlock{
display: none;
}
#noteText {
color: black;
padding: 10px;
vertical-align: top;
width: 100%;
height: auto;
background: white;
min-width: 200px;
border-radius: 0px;
overflow-y: auto;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
/*min-height: 400px;*/
font-size: 14px;
}
#noteText::selection {
background: #ed4014;
color: white;
}
#noteText::-moz-selection {
background: #ed4014;
color: white;
}
#noteText br::selection {
background: #ed4014;
color: white;
}
#noteText br::-moz-selection {
background: #ed4014;
color: white;
}
.noteUrl {
color: #ed4014;
font-weight: bold;
font-family: Merriweather;
}
.noteKey {
color: #ed4014;
font-weight: bold;
font-size: 18px;
font-family: "Bitstream Vera Sans Mono", Consolas, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei"
}
.showBlock{
display: block;
}
.hideBlock{
display: none;
}
</style> </style>

View File

@@ -9,13 +9,10 @@ export function saveNote(noteForm) {
let note = { let note = {
"lock": storeText.substring(0, 1), "lock": storeText.substring(0, 1),
"cipher": storeText.substring(2, 34), "cipher": storeText.substring(2, 34),
"text": storeText.substring(35), "text": storeText.substring(35+16),
"key": noteForm.key "key": noteForm.key
} }
console.log("n"+ storeText)
return axios({ return axios({
url: '/note/' + noteForm.key, url: '/note/' + noteForm.key,
method: 'post', method: 'post',
@@ -78,7 +75,6 @@ export function getNoteMeta(key) {
} }
export function getKeyMeta() { export function getKeyMeta() {
console.log("getKeyMeta");
let keyMeta = {}; let keyMeta = {};
Jquery.ajax({ Jquery.ajax({
method: 'GET', method: 'GET',

14
src/i18n/config/en.js Normal file
View File

@@ -0,0 +1,14 @@
const en = {
message: {
askTodelete: "Are you sure to delete?",
},
content: {
blankTip: "I am Blank.",
},
button: {
ok: "OK",
yes: "Yes",
no: "No",
},
};
export default en;

14
src/i18n/config/zh.js Normal file
View File

@@ -0,0 +1,14 @@
const zh = {
message: {
askTodelete: "是否确定要删除?",
},
content: {
blankTip: "我是布兰克。",
},
button: {
ok: "好的",
yes: "是的",
no: "不",
},
};
export default zh;

16
src/i18n/index.js Normal file
View File

@@ -0,0 +1,16 @@
import Vue from 'vue';
import VueI18n from 'vue-i18n';
Vue.use(VueI18n);
import zh from './config/zh';
import en from './config/en';
const i18n = new VueI18n({
locale: localStorage.getItem('locale') || 'en', // 语言标识
messages: {
zh,
en,
}
})
export default i18n;

View File

@@ -3,7 +3,9 @@ import storage from "@/libs/storage";
import {getSecretKey} from "@/api/lock"; import {getSecretKey} from "@/api/lock";
import escapeHtml from "escape-html"; import escapeHtml from "escape-html";
export function setStoreText(text, secret, password) { export function setStoreText(noteForm, secret, password) {
let text = noteForm.text;
if (!text) { if (!text) {
return; return;
} }
@@ -14,7 +16,7 @@ export function setStoreText(text, secret, password) {
text = "FLAGNOTE#" + text; text = "FLAGNOTE#" + text;
let secretKey = getSecretKey(secret.cipher, password); let secretKey = getSecretKey(noteForm.key, password);
let storeText = aesEncrypt(text, secretKey); let storeText = aesEncrypt(text, secretKey);
storeText = zip(storeText); storeText = zip(storeText);
@@ -23,7 +25,8 @@ export function setStoreText(text, secret, password) {
lock = 1; lock = 1;
} }
storage.local.setText(secret.storeKey + '.text', lock + '|' + secret.cipher + '|' + storeText);
storage.local.setText(secret.storeKey + '.text', lock + '|' + secret.cipher + '|0|'+ noteForm.initTime+'|' + storeText);
} }
@@ -37,11 +40,10 @@ export function clearStoreText(key) {
export function getEscapeText(text) { export function getEscapeText(text) {
let textEscape = escapeHtml(text); let textEscape = escapeHtml(text);
textEscape = textEscape.replaceAll(" ", "&nbsp;"); textEscape = textEscape.replace(new RegExp(' ','gm'), "&nbsp;");
textEscape = textEscape.replaceAll("\r\n", "<br/>"); textEscape = textEscape.replace(new RegExp('\\r\\n','gm'), "<br/>");
textEscape = textEscape.replaceAll("\r", "<br/>"); textEscape = textEscape.replace(new RegExp('\\r','gm'), "<br/>");
textEscape = textEscape.replaceAll("\n", "<br/>"); textEscape = textEscape.replace(new RegExp('\\n','gm'), "<br/>");
textEscape = textEscape.replaceAll("\t", "&nbsp;&nbsp;&nbsp;&nbsp;"); textEscape = textEscape.replace(new RegExp('\\t','gm'), "&nbsp;&nbsp;&nbsp;&nbsp;");
return textEscape; return textEscape;
} }

View File

@@ -6,7 +6,6 @@ class Storage {
} }
class Session { class Session {
setObject(key, value) { setObject(key, value) {
sessionStorage.setItem(key, JSON.stringify(value)); sessionStorage.setItem(key, JSON.stringify(value));
} }
@@ -48,6 +47,70 @@ class Local {
getText(key) { getText(key) {
return localStorage.getItem(key); return localStorage.getItem(key);
} }
getUseSize() {
var size = 0;
for (let i = 0, len = localStorage.length; i < len; i++) {
let key = localStorage.key(i);
if (null == key) {
continue;
}
let value = localStorage.getItem(key);
if (null != value) {
size += value.length;
}
}
return size;
}
getAvailableSize() {
return 5 * 1024 * 1024 - storage.local.getUseSize();
}
dynamicClear(ctt) {
if (storage.local.getAvailableSize() < 1 * 1024 * 1024) {
//remove commited
for (let i = 0, len = localStorage.length; i < len; i++) {
let key = localStorage.key(i);
if (null == key) {
continue;
}
let value = localStorage.getItem(key);
if (key.length == 37 && key.endsWith(".text") && value.length > 50) {
let fl = value.substring(35, 36);
if (fl == "1") {
localStorage.removeItem(key);
}
}
}
//remove expired
if (storage.local.getAvailableSize() < 1 * 1024 * 1024) {
for (let i = 0, len = localStorage.length; i < len; i++) {
let key = localStorage.key(i);
if (null == key) {
continue;
}
let value = localStorage.getItem(key);
if (key.length == 37 && key.endsWith(".text") && value.length > 50) {
let starray = value.split("|");
let fl = starray[2];
let ts = starray[3];
if (fl == "0") {
if (ctt - ts > 3 * 24 * 3600 * 1000) {
localStorage.removeItem(key);
}
}
}
}
}
}
}
} }
const storage = new Storage(); const storage = new Storage();

14
src/libs/utils.js Normal file
View File

@@ -0,0 +1,14 @@
export function isWeixin(){
var useragent = navigator.userAgent;
if (useragent.match(/MicroMessenger/i) == 'MicroMessenger') {
return true;
}
return false;
}
export function isIE() {
if (navigator.userAgent.match(/msie/) != null || navigator.userAgent.match(/trident/) != null) {
return true;
}
return false;
}

View File

@@ -4,36 +4,14 @@ import router from './router'
import axios from 'axios' import axios from 'axios'
import VueAxios from 'vue-axios' import VueAxios from 'vue-axios'
import './plugins/iview.js' import './plugins/iview.js'
import i18n from './i18n/'
//import NProgress from 'nprogress';
//import 'nprogress/nprogress.css';
//顶部页面加载条
// NProgress.configure({
// easing: 'ease',
// speed: 500,
// showSpinner: false,
// trickleSpeed: 200,
// minimum: 0.3
// })
// //路由监听
// router.beforeEach((to, from, next) => {
// NProgress.start();
// next();
// });
// //路由跳转结束
// router.afterEach(() => {
// NProgress.done()
// })
Vue.use(VueAxios, axios) Vue.use(VueAxios, axios)
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({
i18n,
router, router,
render: h => h(App) render: h => h(App)
}).$mount('#app') }).$mount('#app')

View File

@@ -1,16 +1,25 @@
import Vue from 'vue' 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 ErrorView from "@/views/ErrorView.vue";
import BlankNote from '@/views/BlankNote.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";
Vue.use(VueRouter) Vue.use(VueRouter);
let keyMeta = null; var keyMeta = null;
var noteMeta = null;
function getKeyMetaParam() {
return keyMeta;
}
function getNoteMetaParam() {
return noteMeta;
}
function getNoteView() { function getNoteView() {
let path = location.pathname; let path = location.pathname;
@@ -18,7 +27,7 @@ function getNoteView() {
path = "/" + keyMeta.key; path = "/" + keyMeta.key;
} }
let reg = /^\/[abcdefhikmnopqstuvwxyz23456789]{16}$/ let reg = /^\/[abcdefhikmnopqstuvwxyz23456789]{16}$/;
if (!reg.test(path)) { if (!reg.test(path)) {
return; return;
} }
@@ -27,60 +36,65 @@ function getNoteView() {
let storeKey = getStoreKey(key); let storeKey = getStoreKey(key);
if (keyMeta && keyMeta.cipher) { if (keyMeta && keyMeta.cipher) {
storage.session.setObject(storeKey + '.keyMeta', keyMeta); // storage.session.setObject(storeKey + '.keyMeta', keyMeta);
return EditNote; return EditNote;
} }
let noteMeta = null;
noteMeta = getNoteMeta(key); noteMeta = getNoteMeta(key);
if (!noteMeta || !noteMeta.key) { if (!noteMeta || !noteMeta.key) {
let storeText = storage.local.getText(storeKey + '.text'); let storeText = storage.local.getText(storeKey + ".text");
if (storeText) { if (storeText) {
let starray = storeText.split("|");
let commitFlag = starray[2];
if (commitFlag == "1") {
storage.local.delete(storeKey + '.text');
return BlankNote;
} else {
return EditNote; return EditNote;
}
} else { } else {
return BlankNote; return BlankNote;
} }
} }
// storage.session.setObject(storeKey + '.noteMeta', noteMeta);
storage.session.setObject(storeKey + '.noteMeta', noteMeta);
return ViewNote; return ViewNote;
} }
function getHomeRedirect() { function getHomeRedirect() {
let path = location.pathname; let path = location.pathname;
if (path != '/') { if (path != "/") {
return; return;
} }
let km = getKeyMeta(); let km = getKeyMeta();
km.isNew = true; km.isNew = true;
//sessionStorage.setItem(km.getKey() + '.keyMeta', km); //sessionStorage.setItem(km.getKey() + '.keyMeta', km);
keyMeta = km; keyMeta = km;
return '/' + keyMeta.key; return "/" + keyMeta.key;
} }
const routes = [ const routes = [
{ {
path: '/', path: "/",
name: 'home', name: "home",
redirect: getHomeRedirect(), redirect: getHomeRedirect(),
}, },
{ {
path: '/error', path: "/error",
name: 'error', name: "error",
component: ErrorView, component: ErrorView,
}, },
{ {
path: '/:name([abcdefhikmnopqstuvwxyz23456789]{16})', path: "/:name([abcdefhikmnopqstuvwxyz23456789]{16})",
name: 'note', name: "note",
component: getNoteView(), component: getNoteView(),
} meta: { keyMeta: getKeyMetaParam(), noteMeta: getNoteMetaParam() },
] },
];
const router = new VueRouter({ const router = new VueRouter({
routes, routes,
mode: 'history' mode: "history",
}) });
export default router export default router;

View File

@@ -30,61 +30,15 @@
text-align: center; text-align: center;
} }
.ivu-card-bordered { .ivu-card-bordered {
border: 0px solid #dcdee2; border: 0px solid #dcdee2;
border-color: #e8eaec; border-color: #e8eaec;
} }
.noteKey {
color: red;
font-weight: bold;
font-size: 18px;
font-family: "Bitstream Vera Sans Mono", Consolas, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei"
}
</style> </style>
<style> <style>
#noteText {
color: black;
padding: 15px;
vertical-align: top;
width: 100%;
height: auto;
background: white;
min-width: 200px;
border-radius: 0px;
overflow-y: auto;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
/*min-height: 400px;*/
font-size: 14px;
}
#noteText::selection {
background: firebrick;
color: white;
}
#noteText::-moz-selection {
background: firebrick;
color: white;
}
#noteText br::selection {
background: firebrick;
color: white;
}
#noteText br::-moz-selection {
background: firebrick;
color: white;
}
</style> </style>
<template> <template>
<div class="layout" onkeydown="keydown"> <div class="layout" onkeydown="keydown">
@@ -130,7 +84,7 @@
<Card :padding="0"> <Card :padding="0">
<div style="border-left: 0px solid #FF3366;"> <div style="border-left: 0px solid #FF3366;">
<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>blank</h1> <h1>{{$t("content.blankTip")}}</h1>
</div> </div>
</div> </div>
</Card> </Card>

View File

@@ -34,48 +34,39 @@
border-color: #e8eaec; border-color: #e8eaec;
} }
.noteUrl { .fnmodal {
color: red; align-items: center;
font-weight: bold; justify-content: center;
font-family: Merriweather; }
@media print {
@page {
size: portrait;
margin: 20px;
}
body {
margin: 0.8cm;
background-color: #ffffff;
}
.header {
display: none;
}
.layout-footer-center {
display: none;
}
} }
.noteKey {
color: red;
font-weight: bold;
font-size: 18px;
font-family: "Bitstream Vera Sans Mono", Consolas, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei"
}
</style> </style>
<style> <style>
#noteText {
color: black;
padding: 15px;
vertical-align: top;
width: 100%;
height: auto;
background: white;
min-width: 200px;
border-radius: 0px;
overflow-y: auto;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
min-height: 400px;
border: 0px;
font-size: 14px;
}
#noteText::selection {
background: firebrick;
color: white;
}
#noteText::-moz-selection {
background: firebrick;
color: white;
}
</style> </style>
@@ -91,17 +82,21 @@
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }" <Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }"> :lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
<div id="textToTop" v-on:click="toTop()" :class="[toTopState?'showBlock':'hideBlock']"
style="width: 100%;height: 20px;position: absolute;top: 35px;"><div style="display:inline-block;cursor: pointer;padding:2px;"><Icon type="ios-arrow-up" size="28" color="#ed4014"/></div></div>
<div style="background: white;width:100%;height:40px;"> <div style="background: white;width:100%;height:40px;">
<img style="height:40px;float:left;" src="favicon.png"> <img style="height:40px;float:left;" src="favicon.png">
<div style="float:left;width:auto;"> <div style="float:left;width:auto;">
<Button-group size="large"> <Button-group size="large">
<Button type="error" :loading="loading" <Button type="error" :loading="loading" style="margin-left:5px; border-radius: 0px;font-size: 24px;"
style="margin-left:5px; border-radius: 0px;font-size: 24px;" @click="submitNote()" @click="submitNote()" icon="md-cloud-upload"></Button>
icon="md-cloud-upload"></Button>
<Button v-show="model.showDownloadText" type="error"
style="margin-left:5px; border-radius: 0px; font-size: 22px;"
@click="downLoadText()" icon="md-download"></Button>
</Button-group> </Button-group>
</div> </div>
@@ -120,7 +115,7 @@
<Button type="error" style="margin-left:0px; border-radius: 0px;font-size: 24px;" <Button type="error" style="margin-left:0px; border-radius: 0px;font-size: 24px;"
@click="createNote()" icon="md-add"></Button> @click="createNote()" icon="md-add"></Button>
<Button type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;" <Button type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;"
@click="dropNote()" icon="md-trash"></Button> @click="showDeleteModel()" icon="md-trash"></Button>
</Button-group> </Button-group>
</div> </div>
@@ -186,9 +181,8 @@
<Card :padding="0"> <Card :padding="0">
<Form :model="noteForm" :label-width="80"> <Form :model="noteForm" :label-width="80">
<div id="wrapper" style="border-left: 0px solid #FF3366;"> <div id="wrapper" style="border-left: 0px solid #FF3366;">
<Input element-id="noteText" type="textarea" :border="false" v-model="noteForm.text" <Input element-id="noteText" type="textarea" :border="false" v-model="noteForm.text"
:autosize="{ minRows: 30, maxRows: 4096 }" placeholder="Enter something..." v-on:input="log" :autosize="{ minRows: 30, maxRows: 20480 }" placeholder="Enter something..." v-on:input="log"
@on-keydown="down"/> @on-keydown="down"/>
</div> </div>
@@ -217,6 +211,18 @@
style="width: 150px;margin-left:20px;" /> style="width: 150px;margin-left:20px;" />
<p>Content of dialog</p> <p>Content of dialog</p>
</Modal> </Modal>
<Modal v-model="model.showDelete" width="330" footer-hide class-name="fnmodal" :styles="{ borderRadius: 0 }">
<p style="text-align: center;font-size:medium ;margin-bottom: 20px;">
{{$t("message.askTodelete")}}
</p>
<p style="text-align: center;">
<Button type="error" :loading="model.deleting" style="border-radius: 0px;"
@click="dropNote()" >{{$t("button.yes")}}</Button>
</p>
</Modal>
</div> </div>
</template> </template>
@@ -229,6 +235,8 @@ import { saveNote } from "@/api/note";
import { getSecretKey, getStoreKey } from "@/api/lock"; import { getSecretKey, getStoreKey } from "@/api/lock";
import storage from "@/libs/storage"; import storage from "@/libs/storage";
import { setStoreText } from "@/libs/noteStorage"; import { setStoreText } from "@/libs/noteStorage";
import { saveAs } from 'file-saver';
import { isWeixin } from "@/libs/utils";
export default { export default {
name: 'EditNote', name: 'EditNote',
@@ -249,33 +257,54 @@ export default {
storeKey: '', storeKey: '',
secretKey: '', secretKey: '',
cipher: '', cipher: '',
currentTime: '',
initTime: '',
}, },
state: { state: {
lock: 0, lock: 0,
locking: 0, locking: 0,
commited: 0 commited: 0
} },
model:{
showDelete: false,
deleting: false,
showDownloadText: false,
},
toTopState : false,
} }
}, },
created() { created() {
this.model.showDownloadText = !isWeixin();
this.noteForm.key = this.$route.params.name; this.noteForm.key = this.$route.params.name;
let keyMeta = this.$route.meta.keyMeta;
// let noteMeta = this.$route.meta.noteMeta;
let storeKey = getStoreKey(this.noteForm.key); let storeKey = getStoreKey(this.noteForm.key);
this.secret.storeKey = storeKey; this.secret.storeKey = storeKey;
let keyMeta = storage.session.getObject(storeKey + '.keyMeta');
if (keyMeta) { if (keyMeta) {
this.state.lock = 0; this.state.lock = 0;
this.secret.cipher = keyMeta.cipher; this.secret.cipher = keyMeta.cipher;
storage.local.setText(storeKey + '.text', "0|" + this.secret.cipher); this.secret.currentTime = keyMeta.currentTime;
this.noteForm.initTime = keyMeta.currentTime;
storage.local.setText(storeKey + '.text', "0|" + this.secret.cipher + "|0|" + this.secret.currentTime + "|");
storage.session.setObject(storeKey + '.keyMeta', null); storage.session.setObject(storeKey + '.keyMeta', null);
storage.local.dynamicClear(this.secret.currentTime);
} else { } else {
let storeText = storage.local.getText(storeKey + '.text'); let storeText = storage.local.getText(storeKey + '.text');
this.state.lock = parseInt(storeText.substring(0, 1)); let starray = storeText.split('|');
this.secret.cipher = storeText.substring(2, 34) this.state.lock = parseInt(starray[0]);
this.secret.cipher = starray[1];
this.noteForm.initTime = parseInt(starray[3]);
// this.secret.currentTime = noteMeta.currentTime;
// storage.local.dynamicClear(this.secret.currentTime);
} }
if (this.state.lock == 1) { if (this.state.lock == 1) {
this.show = false; this.show = false;
this.noteForm.text = "*****lock*****"; this.noteForm.text = "*****lock*****";
@@ -286,6 +315,38 @@ export default {
this.bindEvent(); this.bindEvent();
let that = this;
window.onscroll = function () {
//变量scrollTop是滚动条滚动时距离顶部的距离
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// //变量windowHeight是可视区的高度
// var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
// //变量scrollHeight是滚动条的总高度
// var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
//滚动条到底部的条件
if (scrollTop >= 20) {
//写后台加载数据的函数
//console.log("距顶部" + scrollTop + "可视区高度" + windowHeight + "滚动条总高度" + scrollHeight);
that.toTopState = true;
} else {
//toTop.style.setProperty("display", "none")
that.toTopState = false;
}
}
}, },
mounted() { mounted() {
}, },
@@ -298,6 +359,9 @@ export default {
computed: {}, computed: {},
watch: {}, watch: {},
methods: { methods: {
toTop(){
window.scrollTo(0, 0);
},
showInput() { showInput() {
this.showPassword = true; this.showPassword = true;
}, },
@@ -312,13 +376,20 @@ export default {
}, },
cancel() { cancel() {
},
downLoadText(){
var blob = new Blob([this.noteForm.text], {type: "application/octet-stream;charset=utf-8"});
saveAs(blob, this.noteForm.key+".txt");
}, },
loadText() { loadText() {
let secretKey = getSecretKey(this.secret.cipher); let secretKey = getSecretKey(this.noteForm.key);
let storeText = storage.local.getText(this.secret.storeKey + '.text'); let storeText = storage.local.getText(this.secret.storeKey + '.text');
if (null != storeText && '' != storeText) { if (null != storeText && '' != storeText) {
let lock = parseInt(storeText.substring(0, 1));
let starray = storeText.split('|');
let lock = parseInt(starray[0]);
if (lock == 1) { if (lock == 1) {
alert("note is encrypt!"); alert("note is encrypt!");
return; return;
@@ -326,8 +397,9 @@ export default {
//let cipher = storeText.substring(2,34) //let cipher = storeText.substring(2,34)
storeText = storeText.substring(35); storeText = starray[4];
if (storeText.length > 0) {
storeText = unzip(storeText); storeText = unzip(storeText);
let plainText = aesDecrypt(storeText, secretKey); let plainText = aesDecrypt(storeText, secretKey);
if (plainText.startsWith("FLAGNOTE#")) { if (plainText.startsWith("FLAGNOTE#")) {
@@ -338,10 +410,14 @@ export default {
alert("password is wrong!") alert("password is wrong!")
} }
} }
} else {
this.noteForm.text = '';
this.state.lock = 0;
}
} }
}, },
log() { log() {
setStoreText(this.noteForm.text, this.secret); setStoreText(this.noteForm, this.secret);
}, },
down(event) { down(event) {
if (event.keyCode == 9) { if (event.keyCode == 9) {
@@ -357,7 +433,7 @@ export default {
event.preventDefault(); event.preventDefault();
} }
this.noteForm.text = event.currentTarget.value; this.noteForm.text = event.currentTarget.value;
setStoreText(event.currentTarget.value, this.secret); setStoreText(this.noteForm, this.secret);
// html2canvas(document.body).then(function (canvas) { // html2canvas(document.body).then(function (canvas) {
// canvas; // canvas;
@@ -365,8 +441,15 @@ export default {
// }); // });
} else if (event.ctrlKey && (event.which == 13)) { } else if (event.ctrlKey && (event.which == 13)) {
let that = this;
this.save().then(res => { this.save().then(res => {
if (res) { if (res) {
let storeText = storage.local.getText(that.secret.storeKey + '.text');
let starray = storeText.split("|");
storage.local.setText(that.secret.storeKey + '.text', starray[0] + '|' + starray[1] + '|1|'+ starray[3] +'|' + starray[4]);
location.reload(); location.reload();
} }
}); });
@@ -385,8 +468,12 @@ export default {
this.loading = true; this.loading = true;
let that = this;
this.save().then(res => { this.save().then(res => {
if (res) { if (res) {
let storeText = storage.local.getText(that.secret.storeKey + '.text');
let starray = storeText.split("|");
storage.local.setText(that.secret.storeKey + '.text', starray[0] + '|' + starray[1] + '|1|'+ starray[3] +'|' + starray[4]);
location.reload(); location.reload();
this.state.locking = 0; this.state.locking = 0;
} }
@@ -407,7 +494,7 @@ export default {
let password = '123456'; let password = '123456';
setStoreText(this.noteForm.text, this.secret, password); setStoreText(this.noteForm, this.secret, password);
this.state.lock = 1 this.state.lock = 1
@@ -438,7 +525,7 @@ export default {
return; return;
} }
let password = '123456'; let password = 'FLAGNOTE';
let storeText = storage.local.getText(this.secret.storeKey + '.text'); let storeText = storage.local.getText(this.secret.storeKey + '.text');
if (storeText) { if (storeText) {
@@ -448,16 +535,16 @@ export default {
alert("note is not encrypt!"); alert("note is not encrypt!");
} }
storeText = storeText.substring(35); storeText = storeText.substring(35 + 16);
storeText = unzip(storeText); storeText = unzip(storeText);
let secretKey = getSecretKey(this.secret.cipher, password); let secretKey = getSecretKey(this.noteForm.key, password);
let plainText = aesDecrypt(storeText, secretKey); let plainText = aesDecrypt(storeText, secretKey);
if (plainText.startsWith("FLAGNOTE#")) { if (plainText.startsWith("FLAGNOTE#")) {
lock = "0"; lock = "0";
} else { } else {
let secretKey = getSecretKey(this.secret.cipher); let secretKey = getSecretKey(this.noteForm.key);
let plainText = aesDecrypt(storeText, secretKey); let plainText = aesDecrypt(storeText, secretKey);
if (plainText.startsWith("FLAGNOTE#")) { if (plainText.startsWith("FLAGNOTE#")) {
lock = "0"; lock = "0";
@@ -469,7 +556,7 @@ export default {
if (lock == '0') { if (lock == '0') {
this.noteForm.text = plainText.substring(9); this.noteForm.text = plainText.substring(9);
this.state.lock = "0"; this.state.lock = "0";
setStoreText(this.noteForm.text, this.secret); setStoreText(this.noteForm, this.secret);
this.show = true; this.show = true;
this.state.locking = "0"; this.state.locking = "0";
} else { } else {
@@ -491,7 +578,11 @@ export default {
createNote() { createNote() {
window.open("/"); window.open("/");
}, },
showDeleteModel() {
this.model.showDelete = true;
},
dropNote() { dropNote() {
this.model.deleting = true;
storage.local.delete(this.secret.storeKey + '.text'); storage.local.delete(this.secret.storeKey + '.text');
storage.session.delete(this.secret.storeKey + '.keyMeta'); storage.session.delete(this.secret.storeKey + '.keyMeta');
location.reload(); location.reload();

View File

@@ -15,6 +15,7 @@
} }
.content { .content {
background: #dddddd; background: #dddddd;
} }
@@ -30,10 +31,6 @@
text-align: center; text-align: center;
} }
.ivu-card-bordered { .ivu-card-bordered {
border: 0px solid #dcdee2; border: 0px solid #dcdee2;
border-color: #e8eaec; border-color: #e8eaec;
@@ -41,58 +38,54 @@
.noteKey { .fnmodal {
color: red; align-items: center;
font-weight: bold; justify-content: center;
font-size: 18px; }
font-family: "Bitstream Vera Sans Mono", Consolas, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei"
@media print {
@page {
size: portrait;
margin: 20px;
}
body {
margin: 0.8cm;
background-color: #ffffff;
}
.header {
display: none;
}
.layout-footer-center {
display: none;
}
} }
</style> </style>
<style> <style>
#noteText {
color: black;
padding: 15px;
vertical-align: top;
width: 100%;
height: auto;
background: white;
min-width: 200px;
border-radius: 0px;
overflow-y: auto;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
/*min-height: 400px;*/
font-size: 14px;
}
#noteText::selection {
background: firebrick;
color: white;
}
#noteText::-moz-selection {
background: firebrick;
color: white;
}
#noteText br::selection {
background: firebrick;
color: white;
}
#noteText br::-moz-selection { .ivu-modal-content {
background: firebrick; border-radius: 0px !important;
color: white;
} }
button span { button span {
font-size: 18px; font-size: 18px;
margin-left: -1px !important; margin-left: -1px !important;
margin-bottom: 5px;
} }
</style> </style>
<template> <template>
<div class="layout" onkeydown="keydown"> <div class="layout">
<Layout> <Layout>
<Affix :offset-top="0"> <Affix :offset-top="0">
@@ -102,8 +95,12 @@ button span {
<Row> <Row>
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }" <Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }"> :lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
<div id="textToTop" v-on:click="toTop()" :class="[toTopState ? 'showBlock' : 'hideBlock']"
style="width: 100%;height: 20px;position: absolute;top: 35px;">
<div style="display:inline-block;cursor: pointer;padding:2px;">
<Icon type="ios-arrow-up" size="28" color="#ed4014" />
</div>
</div>
<div style="background: white;width:100%;height:40px;"> <div style="background: white;width:100%;height:40px;">
<img style="height:40px;float:left;" src="favicon.png"> <img style="height:40px;float:left;" src="favicon.png">
<div style="float:left;width:auto;"> <div style="float:left;width:auto;">
@@ -112,7 +109,17 @@ button span {
<Button type="error" <Button type="error"
style="margin-left:5px; border-radius: 0px;font-size: 24px; font-family: Arial, sans-serif" style="margin-left:5px; border-radius: 0px;font-size: 24px; font-family: Arial, sans-serif"
icon="md-cloud-done">{{ this.noteForm.ttlDesc }}</Button> @click="showShareModel()" icon="md-cloud-done">{{ noteForm.ttlDesc }}</Button>
<!--
<Button type="error"
style="margin-left:5px; border-radius: 0px; font-size: 22px;"
@click="downLoadImage()" icon="md-download">.png</Button>
-->
<Button v-show="model.showDownloadText" type="error"
style="margin-left:5px; border-radius: 0px; font-size: 22px;" @click="downLoadText()"
icon="md-download"></Button>
</Button-group> </Button-group>
@@ -124,7 +131,7 @@ button span {
<Button type="error" style="margin-left:0px; border-radius: 0px;font-size: 24px;" <Button type="error" style="margin-left:0px; border-radius: 0px;font-size: 24px;"
@click="createNote()" icon="md-add"></Button> @click="createNote()" icon="md-add"></Button>
<Button type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;" <Button type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;"
@click="dropNote()" icon="md-trash"></Button> @click="showDeleteModel()" icon="md-trash"></Button>
</Button-group> </Button-group>
</div> </div>
@@ -157,6 +164,7 @@ button span {
</Row> </Row>
</div> </div>
</Header> </Header>
</Affix> </Affix>
<Content class="content"> <Content class="content">
<div style="min-height: 650px;"> <div style="min-height: 650px;">
@@ -166,10 +174,7 @@ button span {
<Card :padding="0"> <Card :padding="0">
<div style="border-left: 0px solid #FF3366;"> <div style="border-left: 0px solid #FF3366;">
<div id="noteText" style="text-align: left;min-height: 650px;" class="monoFt" <div id="noteText" style="text-align: left;min-height: 650px;" class="monoFt"
v-html="this.noteForm.escapeText"> v-html="noteForm.escapeText"></div>
view2
</div>
</div> </div>
</Card> </Card>
</Col> </Col>
@@ -178,12 +183,36 @@ button span {
</Content> </Content>
<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.showShare" width="330" footer-hide class-name="qrmodal" :styles="{ borderRadius: 0 }">
<p style="text-align: center;">
<canvas id="qrimg" class=""></canvas>
</p>
<p style="text-align: center;">
<span id="tag-copy" class="noteUrl" :data-clipboard-text="noteForm.noteUrl" data-clipboard-action="copy">{{
noteForm.noteUrl
}}</span>
</p>
</Modal>
<Modal v-model="model.showDelete" width="330" footer-hide class-name="fnmodal" :styles="{ borderRadius: 0 }">
<p style="text-align: center;font-size:medium;margin-bottom: 20px;">
{{$t("message.askTodelete")}}
</p>
<p style="text-align: center;">
<Button type="error" :loading="model.delete" style="border-radius: 0px;" @click="dropNote()">{{$t("button.yes")}}</Button>
</p>
</Modal>
</div> </div>
</template> </template>
<script> <script>
@@ -194,6 +223,11 @@ import { getSecretKey, getStoreKey } from "@/api/lock";
import { deleteNote } from "@/api/note"; import { deleteNote } from "@/api/note";
import storage from "@/libs/storage"; import storage from "@/libs/storage";
import { getEscapeText } from "@/libs/noteStorage"; import { getEscapeText } from "@/libs/noteStorage";
import QRCode from "qrcode";
import Clipboard from "clipboard";
import { saveAs } from 'file-saver';
import { isWeixin } from "@/libs/utils";
// import html2canvas from 'html2canvas';
export default { export default {
name: 'ViewNote', name: 'ViewNote',
@@ -203,6 +237,7 @@ export default {
return { return {
noteForm: { noteForm: {
url: '', url: '',
noteUrl: '',
text: '', text: '',
escapeText: '', escapeText: '',
key: '', key: '',
@@ -215,36 +250,122 @@ export default {
storeKey: '', storeKey: '',
secretKey: '', secretKey: '',
cipher: '', cipher: '',
currentTime: '',
}, },
state: { state: {
lock: 0, lock: 0,
locking: 0, locking: 0,
initTime: null, initTime: null,
initTtl: null, initTtl: null,
commited: 0 commited: 0,
} },
model: {
showDelete: false,
showShare: false,
deleting: false,
showDownloadText: true,
},
toTopState: false,
} }
}, },
created() { created() {
this.model.showDownloadText = !isWeixin();
let noteMeta = this.$route.meta.noteMeta;
this.noteForm.key = this.$route.params.name; this.noteForm.key = this.$route.params.name;
this.noteForm.noteUrl = "https://flagnote.com/" + this.noteForm.key;
let storeKey = getStoreKey(this.noteForm.key); let storeKey = getStoreKey(this.noteForm.key);
this.secret.storeKey = storeKey; this.secret.storeKey = storeKey;
let noteMeta = storage.session.getObject(storeKey + '.noteMeta');
if (noteMeta) { if (noteMeta) {
this.state.lock = noteMeta.lock; this.state.lock = noteMeta.lock;
this.state.initTime = new Date().getTime(); this.state.initTime = new Date().getTime();
this.state.initTtl = noteMeta.ttl; this.state.initTtl = noteMeta.ttl;
this.secret.cipher = noteMeta.cipher; this.secret.currentTime = noteMeta.currentTime;
this.secret.cipher = "00000000000000000000000000000000";//noteMeta.cipher; //读者有没有值可配置
this.noteForm.md5 = noteMeta.md5; this.noteForm.md5 = noteMeta.md5;
this.noteForm.ttl = noteMeta.ttl; this.noteForm.ttl = noteMeta.ttl;
this.startClock();
this.startClock();
this.loadText(); this.loadText();
storage.local.dynamicClear(this.secret.currentTime);
}
this.bindEvent();
var clipboard = new Clipboard("#tag-copy")
let that = this;
clipboard.on('success', function () {
//console.log("url copied")
//that.$Message.success({content:'url copied',duration: 10,closable:true});
that.$Message.success({ content: 'url copied' });
});
clipboard.on('error', function () {
that.$Message.error('not allow to copy');
});
window.onscroll = function () {
//变量scrollTop是滚动条滚动时距离顶部的距离
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// //变量windowHeight是可视区的高度
// var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
// //变量scrollHeight是滚动条的总高度
// var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
//滚动条到底部的条件
if (scrollTop >= 20) {
//写后台加载数据的函数
//console.log("距顶部" + scrollTop + "可视区高度" + windowHeight + "滚动条总高度" + scrollHeight);
that.toTopState = true;
} else {
//toTop.style.setProperty("display", "none")
that.toTopState = false;
}
} }
this.bindEvent();
}, },
methods: { methods: {
downLoadText() {
var blob = new Blob([this.noteForm.text], { type: "application/octet-stream;charset=utf-8" });
saveAs(blob, this.noteForm.key + ".txt");
},
downLoadImage() {
//let that = this;
//html2canvas(document.getElementById("noteText")).then(function(canvas) {
// var canvas = document.getElementById("my-canvas");
//canvas.toBlob(function(blob) {
// saveAs(blob, that.noteForm.key+".png");
// });
// alert(canvas)
// document.body.appendChild(canvas);
//});
},
toTop() {
window.scrollTo(0, 0);
this.downLoadImage();
},
startClock() { startClock() {
let that = this; let that = this;
window.setInterval(function () { window.setInterval(function () {
@@ -268,7 +389,6 @@ export default {
if (that.noteForm.ttl <= 0) { if (that.noteForm.ttl <= 0) {
storage.local.delete(that.secret.storeKey + '.text'); storage.local.delete(that.secret.storeKey + '.text');
storage.session.delete(that.secret.storeKey + '.keyMeta');
location.reload(); location.reload();
} }
}, 1000) }, 1000)
@@ -282,37 +402,66 @@ export default {
createNote() { createNote() {
window.open("/"); window.open("/");
}, },
showShareModel() {
this.model.showShare = true;
let qrimg = document.getElementById("qrimg");
let qrurl = "https://flagnote.com/" + this.noteForm.key;
var opts = {
errorCorrectionLevel: 'Q',
type: 'image/jpeg',
quality: 0.9,
height: 192,
width: 192,
margin: 1,
color: {
dark: "#ed4014",
light: "#FFFFFF"
}
}
QRCode.toCanvas(qrimg, qrurl, opts)
},
showDeleteModel() {
this.model.showDelete = true;
},
dropNote() { dropNote() {
this.model.deleting = true;
let that = this;
deleteNote(this.noteForm.key).then(res => { deleteNote(this.noteForm.key).then(res => {
if (res) { if (res) {
storage.local.delete(this.secret.storeKey + '.text'); storage.local.delete(that.secret.storeKey + '.text');
storage.session.delete(this.secret.storeKey + '.keyMeta'); storage.session.delete(that.secret.storeKey + '.keyMeta');
location.reload(); location.reload();
} else {
that.model.deleting = false;
} }
}); });
}, },
loadText() { loadText() {
let password; let password;
if (this.noteForm.lock == 1) { if (this.noteForm.lock == 1) {
password = "123456" password = "FLAGNOTE"; //默认密码
} }
if (!password) { if (!password) {
password = ""; password = "";
} }
let secretKey = getSecretKey(this.secret.cipher, password);
let secretKey = getSecretKey(this.noteForm.key, password);
let storeText = storage.local.getText(this.secret.storeKey + '.text'); let storeText = storage.local.getText(this.secret.storeKey + '.text');
if (!storeText || md5(storeText.substring(35)) != this.noteForm.md5) { if (!storeText || (md5(storeText.substring(51)) != this.noteForm.md5)) {
let note = this.getNote(this.noteForm.key); let note = this.getNote(this.noteForm.key);
storeText = this.noteForm.lock + '|' + this.secret.cipher + '|' + note.text; storeText = this.noteForm.lock + '|' + this.secret.cipher + '|1|' + this.noteForm.currentTime + '|' + note.text;
storage.local.setText(this.secret.storeKey + '.text', storeText); storage.local.setText(this.secret.storeKey + '.text', storeText);
} else {
var starray = storeText.split('|');
storage.local.setText(this.secret.storeKey + '.text', starray[0] + "|" + starray[1] + "|1|" + starray[3] + "|" + starray[4]);
} }
if (storeText) { if (storeText) {
storeText = unzip(storeText.substring(35)); storeText = unzip(storeText.split('|')[4]);
let plainText = aesDecrypt(storeText, secretKey); let plainText = aesDecrypt(storeText, secretKey);
if (plainText.startsWith("FLAGNOTE#")) { if (plainText.startsWith("FLAGNOTE#")) {
this.noteForm.text = plainText.substring(9); this.noteForm.text = plainText.substring(9);

View File

@@ -1,16 +1,36 @@
const {defineConfig} = require('@vue/cli-service') const { defineConfig } = require("@vue/cli-service");
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = defineConfig({ module.exports = defineConfig({
configureWebpack: {
plugins: [
new CompressionPlugin({
algorithm: "gzip", // 使用gzip压缩
test: /\.js$|\.html$|\.png$|\.jpg$|\.svg$|\.css$/, // 匹配文件名
filename: "[path][base].gz[query]", // 压缩后的文件名(保持原文件名,后缀加.gz)
minRatio: 1, // 压缩率小于1才会压缩
threshold: 5120, // 对超过10k的数据压缩
deleteOriginalAssets: false, // 是否删除未压缩的源文件谨慎设置如果希望提供非gzip的资源可不设置或者设置为false比如删除打包后的gz后还可以加载到原始资源文件
}),
],
},
transpileDependencies: true, transpileDependencies: true,
chainWebpack: (config) => {
config.plugin("html").tap((args) => {
args[0].title = "flagnote.com";
return args;
});
},
devServer: { devServer: {
proxy: { proxy: {
'/note': { "/note": {
target: 'http://localhost:55555/', // 后台接口域名 target: "http://12coffee.club:3333/", // 后台接口域名
secure: false, // 如果是https接口需要配置这个参数 secure: false, // 如果是https接口需要配置这个参数
changeOrigin: true, //是否跨域 changeOrigin: true, //是否跨域
pathRewrite: { pathRewrite: {
// '^/': '/' // '^/': '/'
} },
} },
} },
} },
}) });

6284
yarn.lock Normal file

File diff suppressed because it is too large Load Diff