add copy feature

This commit is contained in:
RainSun 2020-03-07 20:43:26 +08:00
parent 5c2a0b5aa8
commit 95f6f3b8c9
2 changed files with 403 additions and 332 deletions

View File

@ -128,8 +128,10 @@ export function lang() {
options:['6 位', '12 位', '18 位', '24 位', '32 位'] options:['6 位', '12 位', '18 位', '24 位', '32 位']
}, },
settings:['包含大写', '包含小写', '包含数字', '包含符号'], settings:['包含大写', '包含小写', '包含数字', '包含符号'],
actions: ['生成','关闭'], actions: ['生成', '复制', '关闭'],
code_res_empty: '未生成', code_res_empty: '未生成',
copy_successful: '(复制成功)',
copy_failed: '(复制失败)',
} }
}, },
EN: { EN: {
@ -145,8 +147,10 @@ export function lang() {
options:['6 Digit', '12 Digit', '18 Digit', '24 Digit', '32 Digit'] options:['6 Digit', '12 Digit', '18 Digit', '24 Digit', '32 Digit']
}, },
settings:['Contain Uppercase', 'Contain Lowercase', 'Contain Number', 'Contain Symbol'], settings:['Contain Uppercase', 'Contain Lowercase', 'Contain Number', 'Contain Symbol'],
actions: ['Generate','Close'], actions: ['Generate', 'Copy','Close'],
code_res_empty: 'Not generated', code_res_empty: 'Not generated',
copy_successful: '(Copy successful)',
copy_failed: '(Failed to copy)',
} }
} }
}, },
@ -278,6 +282,14 @@ export function lang() {
CHS:{ CHS:{
title: '更新日志', title: '更新日志',
timeline: [ timeline: [
{
label: '新建密码记录生成的密码支持复制',
tag:'功能更新',
content: [
'在新建密码页生成密码支持一键复制',
'2020-03-07'
]
},
{ {
label: '修复云端最后修改时间不更新的问题', label: '修复云端最后修改时间不更新的问题',
tag:'bug修复', tag:'bug修复',
@ -363,6 +375,14 @@ export function lang() {
EN:{ EN:{
title: 'Update Log', title: 'Update Log',
timeline: [ timeline: [
{
label: 'Generated passwords support replication',
tag:'Feature update',
content: [
'Generate a password on the new password page',
'2020-03-07'
]
},
{ {
label: 'Fix the problem that the last modification time of the cloud is not updated', label: 'Fix the problem that the last modification time of the cloud is not updated',
tag:'Bug fix', tag:'Bug fix',

View File

@ -1,357 +1,408 @@
<template> <template>
<div class="add"> <div class="add">
<md-app md-waterfall md-mode="fixed"> <md-app md-waterfall md-mode="fixed">
<md-app-toolbar class="md-primary toolbar"> <md-app-toolbar class="md-primary toolbar">
<div class="md-toolbar-section-start"> <div class="md-toolbar-section-start">
<md-button class="md-icon-button" @click="back()"><md-icon>arrow_back</md-icon></md-button> <md-button class="md-icon-button" @click="back()">
<h3 class="md-title" style="flex: 1">{{ id_cache ? lang.title[1] : lang.title[0] }}</h3> <md-icon>arrow_back</md-icon>
</div> </md-button>
</md-app-toolbar> <h3 class="md-title" style="flex: 1">{{ id_cache ? lang.title[1] : lang.title[0] }}</h3>
<md-app-content> </div>
<v-touch @swiperight="back()" :swipe-options="{ direction: 'horizontal' }"> </md-app-toolbar>
<div ref="list_placeholder" style="height: 54px;"></div> <md-app-content>
<md-field :class="title_verify ? '' : 'md-invalid'"> <v-touch @swiperight="back()" :swipe-options="{ direction: 'horizontal' }">
<label>{{ lang.subheader[0] }}</label> <div ref="list_placeholder" style="height: 54px;"></div>
<md-input v-model="title" required></md-input> <md-field :class="title_verify ? '' : 'md-invalid'">
<span class="md-error">{{ lang.empty_error[0] }}</span> <label>{{ lang.subheader[0] }}</label>
</md-field> <md-input v-model="title" required></md-input>
<span class="md-error">{{ lang.empty_error[0] }}</span>
</md-field>
<md-field :class="user_name_verify ? '' : 'md-invalid'"> <md-field :class="user_name_verify ? '' : 'md-invalid'">
<label>{{ lang.subheader[1] }}</label> <label>{{ lang.subheader[1] }}</label>
<md-input v-model="user_name" required></md-input> <md-input v-model="user_name" required></md-input>
<span class="md-error">{{ lang.empty_error[1] }}</span> <span class="md-error">{{ lang.empty_error[1] }}</span>
</md-field> </md-field>
<md-field :class="password_verify ? '' : 'md-invalid'"> <md-field :class="password_verify ? '' : 'md-invalid'">
<label>{{ lang.subheader[2] }}</label> <label>{{ lang.subheader[2] }}</label>
<md-input v-model="password" required></md-input> <md-input v-model="password" required></md-input>
<span class="md-error">{{ lang.empty_error[2] }}</span> <span class="md-error">{{ lang.empty_error[2] }}</span>
<span class="md-caption" style="color:#448AFF;" @click="show_dialog = true">生成密码</span> <span class="md-caption" style="color:#448AFF;" @click="show_dialog = true">生成密码</span>
</md-field> </md-field>
<md-field> <md-field>
<label>{{ lang.subheader[3] }}</label> <label>{{ lang.subheader[3] }}</label>
<md-input v-model="web_address"></md-input> <md-input v-model="web_address"></md-input>
</md-field> </md-field>
<md-field> <md-field>
<label>{{ lang.subheader[4] }}</label> <label>{{ lang.subheader[4] }}</label>
<md-textarea v-model="node"></md-textarea> <md-textarea v-model="node"></md-textarea>
</md-field> </md-field>
<md-button class="md-raised md-primary expand" @click="judgeContent()">{{ lang.enter }}</md-button> <md-button class="md-raised md-primary expand" @click="judgeContent()">{{ lang.enter }}</md-button>
<md-dialog :md-active.sync="show_dialog" style="min-width: 50%;"> <md-dialog :md-active.sync="show_dialog" style="min-width: 50%;">
<md-dialog-title>生成密码</md-dialog-title> <md-dialog-title>生成密码{{copy_state}}</md-dialog-title>
<md-list> <md-list>
<!-- 生成结果 --> <!-- 生成结果 -->
<md-subheader class="md-primary">{{ lang.generator.subheader[0] }}</md-subheader> <md-subheader class="md-primary">{{ lang.generator.subheader[0] }}</md-subheader>
<md-list-item> <md-list-item>
<p>{{ password ? password : lang.generator.code_res_empty }}</p> <p>{{ password ? password : lang.generator.code_res_empty }}</p>
</md-list-item> </md-list-item>
<!-- settings --> <!-- settings -->
<md-subheader class="md-primary">{{ lang.generator.subheader[1] }}</md-subheader> <md-subheader class="md-primary">{{ lang.generator.subheader[1] }}</md-subheader>
<!-- 长度设置 --> <!-- 长度设置 -->
<md-list-item> <md-list-item>
<md-field> <md-field>
<label for="expired_time">{{ lang.generator.length_setter.label }}</label> <label for="expired_time">{{ lang.generator.length_setter.label }}</label>
<md-select v-model="code_length" name="code_length" id="code_length"> <md-select v-model="code_length" name="code_length" id="code_length">
<md-option value="6">{{ lang.generator.length_setter.options[0] }}</md-option> <md-option value="6">{{ lang.generator.length_setter.options[0] }}</md-option>
<md-option value="12">{{ lang.generator.length_setter.options[1] }}</md-option> <md-option value="12">{{ lang.generator.length_setter.options[1] }}</md-option>
<md-option value="18">{{ lang.generator.length_setter.options[2] }}</md-option> <md-option value="18">{{ lang.generator.length_setter.options[2] }}</md-option>
<md-option value="24">{{ lang.generator.length_setter.options[3] }}</md-option> <md-option value="24">{{ lang.generator.length_setter.options[3] }}</md-option>
<md-option value="32">{{ lang.generator.length_setter.options[4] }}</md-option> <md-option value="32">{{ lang.generator.length_setter.options[4] }}</md-option>
</md-select> </md-select>
</md-field> </md-field>
</md-list-item> </md-list-item>
<!-- 大写字母 --> <!-- 大写字母 -->
<md-list-item> <md-list-item>
<span class="md-list-item-text">{{ lang.generator.settings[0] }}</span> <span class="md-list-item-text">{{ lang.generator.settings[0] }}</span>
<md-switch v-model="have_upper" class="md-primary"></md-switch> <md-switch v-model="have_upper" class="md-primary"></md-switch>
</md-list-item> </md-list-item>
<!-- 小写字母 --> <!-- 小写字母 -->
<md-list-item> <md-list-item>
<span class="md-list-item-text">{{ lang.generator.settings[1] }}</span> <span class="md-list-item-text">{{ lang.generator.settings[1] }}</span>
<md-switch v-model="have_lower" class="md-primary"></md-switch> <md-switch v-model="have_lower" class="md-primary"></md-switch>
</md-list-item> </md-list-item>
<!-- 数字 --> <!-- 数字 -->
<md-list-item> <md-list-item>
<span class="md-list-item-text">{{ lang.generator.settings[2] }}</span> <span class="md-list-item-text">{{ lang.generator.settings[2] }}</span>
<md-switch v-model="have_num" class="md-primary"></md-switch> <md-switch v-model="have_num" class="md-primary"></md-switch>
</md-list-item> </md-list-item>
<!-- 符号 --> <!-- 符号 -->
<md-list-item> <md-list-item>
<span class="md-list-item-text">{{ lang.generator.settings[3] }}</span> <span class="md-list-item-text">{{ lang.generator.settings[3] }}</span>
<md-switch v-model="have_symbol" class="md-primary"></md-switch> <md-switch v-model="have_symbol" class="md-primary"></md-switch>
</md-list-item> </md-list-item>
</md-list> </md-list>
<md-dialog-actions> <md-dialog-actions>
<md-button class="md-primary" @click="generateStart()">{{ lang.generator.actions[0] }}</md-button> <md-button class="md-primary" @click="generateStart()">{{ lang.generator.actions[0] }}</md-button>
<md-button class="md-primary" @click="show_dialog = false">{{ lang.generator.actions[1] }}</md-button> <md-button
</md-dialog-actions> class="md-primary"
</md-dialog> v-clipboard:copy="password"
</v-touch> v-clipboard:success="onCopyCode"
</md-app-content> v-clipboard:error="onErrorCode"
</md-app> >{{ lang.generator.actions[1] }}</md-button>
</div> <md-button
class="md-primary"
@click="show_dialog = false"
>{{ lang.generator.actions[2] }}</md-button>
</md-dialog-actions>
</md-dialog>
</v-touch>
</md-app-content>
</md-app>
</div>
</template> </template>
<script> <script>
// @ is an alias to /src // @ is an alias to /src
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from "vuex";
import { encrypt, decrypt, encryptMainCode, decryptMainCode } from '@/utils/aes.js'; import {
import { lang } from '@/utils/language.js'; encrypt,
import { setHtmlFontSize } from '@/utils/px2rem.js'; decrypt,
import { generatePassword } from '@/utils/generator.js'; encryptMainCode,
decryptMainCode
} from "@/utils/aes.js";
import { lang } from "@/utils/language.js";
import { setHtmlFontSize } from "@/utils/px2rem.js";
import { generatePassword } from "@/utils/generator.js";
export default { export default {
name: 'Add', name: "Add",
data() { data() {
return { return {
clientHeight: '', clientHeight: "",
title: '', title: "",
user_name: '', user_name: "",
password: '', password: "",
node: '', node: "",
web_address: '', web_address: "",
id_cache: '', id_cache: "",
open_count_cache: '', open_count_cache: "",
title_verify: true, title_verify: true,
user_name_verify: true, user_name_verify: true,
password_verify: true, password_verify: true,
lang: '', lang: "",
show_dialog: false, show_dialog: false,
// //
have_upper: true, have_upper: true,
// //
have_lower: true, have_lower: true,
// //
have_num: true, have_num: true,
// //
have_symbol: false, have_symbol: false,
// //
code_length: 12 code_length: 12,
}; //
}, copy_state: ""
computed: { };
...mapState(['row_data', 'row_pwd', 'settings']) },
}, computed: {
methods: { ...mapState(["row_data", "row_pwd", "settings"])
...mapActions(['setRowData', 'setRowPwd']), },
// md-app methods: {
changeFixed(clientHeight) { ...mapActions(["setRowData", "setRowPwd"]),
// // md-app
// console.log(clientHeight); changeFixed(clientHeight) {
// window.document.getElementsByClassName('md-content')[0].style.minHeight = clientHeight + 'px'; //
this.$refs.list_placeholder.parentNode.parentNode.style.maxHeight = clientHeight + 'px'; // console.log(clientHeight);
this.$refs.list_placeholder.parentNode.style.minHeight = clientHeight - 32 + 'px'; // window.document.getElementsByClassName('md-content')[0].style.minHeight = clientHeight + 'px';
window.document.documentElement.setAttribute('data-theme', this.settings.is_dark_mode ? 'dark' : 'light'); this.$refs.list_placeholder.parentNode.parentNode.style.maxHeight =
}, clientHeight + "px";
// this.$refs.list_placeholder.parentNode.style.minHeight =
init() { clientHeight - 32 + "px";
// vuex window.document.documentElement.setAttribute(
this.$store.replaceState(Object.assign(this.$store.state, JSON.parse(localStorage.getItem('storeState')))); "data-theme",
// this.settings.is_dark_mode ? "dark" : "light"
if (Object.keys(this.row_pwd).length != 0) { );
// },
let now = new Date().getTime(); //
if (now - this.row_pwd.create_time < this.settings.expired_time) { init() {
// // vuex
// this.$store.replaceState(
this.initLanguage(); Object.assign(
if (this.$route.params.modify_content) { this.$store.state,
// JSON.parse(localStorage.getItem("storeState"))
let content = this.$route.params.modify_content; )
this.title = content.title; );
this.user_name = content.user_name; //
this.password = content.password; if (Object.keys(this.row_pwd).length != 0) {
this.node = content.node; //
this.web_address = content.web_address; let now = new Date().getTime();
this.id_cache = content.id; if (now - this.row_pwd.create_time < this.settings.expired_time) {
this.open_count_cache = content.open_count; //
} //
return; this.initLanguage();
} else { if (this.$route.params.modify_content) {
// //
this.turnToHome('密码超时'); let content = this.$route.params.modify_content;
} this.title = content.title;
} else { this.user_name = content.user_name;
// this.password = content.password;
this.turnToHome('无密码'); this.node = content.node;
} this.web_address = content.web_address;
}, this.id_cache = content.id;
this.open_count_cache = content.open_count;
}
return;
} else {
//
this.turnToHome("密码超时");
}
} else {
//
this.turnToHome("无密码");
}
},
// //
initLanguage() { initLanguage() {
if (this.settings.is_chinese) { if (this.settings.is_chinese) {
this.lang = lang().add.CHS; this.lang = lang().add.CHS;
} else { } else {
this.lang = lang().add.EN; this.lang = lang().add.EN;
} }
console.log('语言配置完成'); console.log("语言配置完成");
}, },
// //
judgeContent() { judgeContent() {
// flag // flag
let can_continue = true; let can_continue = true;
// title // title
if (!(this.title = this.title.trim())) { if (!(this.title = this.title.trim())) {
can_continue = false; can_continue = false;
this.title_verify = false; this.title_verify = false;
} }
// user_name // user_name
if (!(this.user_name = this.user_name.trim())) { if (!(this.user_name = this.user_name.trim())) {
can_continue = false; can_continue = false;
this.user_name_verify = false; this.user_name_verify = false;
} }
// password // password
if (!(this.password = this.password.trim())) { if (!(this.password = this.password.trim())) {
can_continue = false; can_continue = false;
this.password_verify = false; this.password_verify = false;
} }
// flag // flag
if (can_continue) this.submit(); if (can_continue) this.submit();
}, },
// //
submit() { submit() {
// //
if (this.id_cache) { if (this.id_cache) {
console.log('覆写拦截器生效'); console.log("覆写拦截器生效");
this.reWrite(); this.reWrite();
return; return;
} }
// //
let data_list; let data_list;
// //
let code = { let code = {
id: this.createId(), id: this.createId(),
open_count: 0, open_count: 0,
title: this.title, title: this.title,
user_name: this.user_name, user_name: this.user_name,
password: this.password, password: this.password,
node: this.node, node: this.node,
web_address: this.web_address web_address: this.web_address
}; };
// //
let main_code_decrpt = decryptMainCode(this.row_pwd.main_code); let main_code_decrpt = decryptMainCode(this.row_pwd.main_code);
// //
if (this.row_data) { if (this.row_data) {
// //
// //
let data_decrypt = decrypt(main_code_decrpt, this.row_data); let data_decrypt = decrypt(main_code_decrpt, this.row_data);
// json // json
data_list = JSON.parse(data_decrypt); data_list = JSON.parse(data_decrypt);
data_list.push(code); data_list.push(code);
} else { } else {
// //
data_list = [code]; data_list = [code];
} }
let data_list_aes = encrypt(main_code_decrpt, data_list); let data_list_aes = encrypt(main_code_decrpt, data_list);
this.setRowData([data_list_aes, this]); this.setRowData([data_list_aes, this]);
console.log('新加密信息保存成功,返回Home'); console.log("新加密信息保存成功,返回Home");
this.back(); this.back();
}, },
reWrite() { reWrite() {
let data_list; let data_list;
// //
let code = { let code = {
id: this.id_cache, id: this.id_cache,
open_count: this.open_count_cache, open_count: this.open_count_cache,
title: this.title, title: this.title,
user_name: this.user_name, user_name: this.user_name,
password: this.password, password: this.password,
node: this.node, node: this.node,
web_address: this.web_address web_address: this.web_address
}; };
// //
let main_code_decrpt = decryptMainCode(this.row_pwd.main_code); let main_code_decrpt = decryptMainCode(this.row_pwd.main_code);
// //
let data_decrypt = decrypt(main_code_decrpt, this.row_data); let data_decrypt = decrypt(main_code_decrpt, this.row_data);
// json // json
data_list = JSON.parse(data_decrypt); data_list = JSON.parse(data_decrypt);
// //
for (let i in data_list) { for (let i in data_list) {
// //
if (data_list[i].id == code.id) { if (data_list[i].id == code.id) {
// //
data_list[i] = code; data_list[i] = code;
} }
} }
let data_list_aes = encrypt(main_code_decrpt, data_list); let data_list_aes = encrypt(main_code_decrpt, data_list);
this.setRowData([data_list_aes, this]); this.setRowData([data_list_aes, this]);
console.log('新加密信息覆写成功,返回详情'); console.log("新加密信息覆写成功,返回详情");
this.back(); this.back();
}, },
// //
back() { back() {
this.$router.go(-1); this.$router.go(-1);
}, },
// Home // Home
turnToHome(msg) { turnToHome(msg) {
console.log(msg); console.log(msg);
this.$router.replace('/'); this.$router.replace("/");
}, },
// //
createId() { createId() {
// //
let time = new Date().getTime(); let time = new Date().getTime();
// //
let random = Math.floor(Math.random() * 100); let random = Math.floor(Math.random() * 100);
// 100 // 100
random < 10 ? (random = '0' + random.toString()) : (random = random.toString()); random < 10
// ? (random = "0" + random.toString())
let id = time.toString() + random; : (random = random.toString());
return id; //
}, let id = time.toString() + random;
return id;
},
// //
generateStart() { generateStart() {
this.password = generatePassword(this.code_length, this.have_lower, this.have_upper, this.have_num, this.have_symbol); this.password = generatePassword(
} this.code_length,
}, this.have_lower,
created() { this.have_upper,
this.lang = lang().add.CHS; this.have_num,
console.log('临时语言系统加载完成'); this.have_symbol
this.init(); );
}, },
mounted() {
// //
this.clientHeight = `${document.documentElement.clientHeight}`; onCopyCode() {
//document.body.clientWidth; this.copy_state = this.lang.generator.copy_successful;
window.onresize = function temp() { setTimeout(() => {
this.clientHeight = `${document.documentElement.clientHeight}`; this.copy_state = "";
setHtmlFontSize(); }, 2000);
}.bind(this); },
}, //
watch: { onErrorCode() {
// `clientHeight` this.copy_state = this.lang.generator.copy_failed;
clientHeight: function() { setTimeout(() => {
this.changeFixed(this.clientHeight); this.copy_state = "";
} }, 2000);
}, }
beforeDestroy() {}, },
components: {} created() {
this.lang = lang().add.CHS;
console.log("临时语言系统加载完成");
this.init();
},
mounted() {
//
this.clientHeight = `${document.documentElement.clientHeight}`;
//document.body.clientWidth;
window.onresize = function temp() {
this.clientHeight = `${document.documentElement.clientHeight}`;
setHtmlFontSize();
}.bind(this);
},
watch: {
// `clientHeight`
clientHeight: function() {
this.changeFixed(this.clientHeight);
}
},
beforeDestroy() {},
components: {}
}; };
</script> </script>
<style scoped lang="scss" type="text/scss"> <style scoped lang="scss" type="text/scss">
@import '../../style/main'; @import "../../style/main";
.add { .add {
width: 100%; width: 100%;
min-height: 100%; min-height: 100%;
background: #fff; background: #fff;
.expand { .expand {
width: 100%; width: 100%;
margin: 0 !important; margin: 0 !important;
min-height: 1.2rem !important; min-height: 1.2rem !important;
} }
.toolbar { .toolbar {
position: fixed !important; position: fixed !important;
} }
} }
</style> </style>