Support password generation when creating new password records

This commit is contained in:
RainSun 2020-03-05 11:54:57 +08:00
parent 13f4025c29
commit 620cf998d9
2 changed files with 199 additions and 93 deletions

View File

@ -119,13 +119,35 @@ export function lang() {
title: ['新建密码', '编辑'], title: ['新建密码', '编辑'],
subheader: ['密码标题', '用户名', '密码', '网址', '备注...'], subheader: ['密码标题', '用户名', '密码', '网址', '备注...'],
enter: '提交', enter: '提交',
empty_error: ['密码标题不可为空', '用户名不可为空', '密码不可为空'] empty_error: ['密码标题不可为空', '用户名不可为空', '密码不可为空'],
generator: {
title: '生成密码',
subheader: ['结果', '设置'],
length_setter:{
label: '密码长度',
options:['6 位', '12 位', '18 位', '24 位', '32 位']
},
settings:['包含大写', '包含小写', '包含数字', '包含符号'],
actions: ['生成','关闭'],
code_res_empty: '未生成',
}
}, },
EN: { EN: {
title: ['Add New Code', 'Edit'], title: ['Add New Code', 'Edit'],
subheader: ['Code Title', 'Username', 'Password', 'Web address', 'Node'], subheader: ['Code Title', 'Username', 'Password', 'Web address', 'Node'],
enter: 'Enter', enter: 'Enter',
empty_error: ['Title can not be none.', 'Username can not be none.', 'Password can not be none.'] empty_error: ['Title can not be none.', 'Username can not be none.', 'Password can not be none.'],
generator: {
title: 'Generate Password',
subheader: ['Results (click to copy)', 'Settings'],
length_setter:{
label: 'Password Length',
options:['6 Digit', '12 Digit', '18 Digit', '24 Digit', '32 Digit']
},
settings:['Contain Uppercase', 'Contain Lowercase', 'Contain Number', 'Contain Symbol'],
actions: ['Generate','Close'],
code_res_empty: 'Not generated',
}
} }
}, },
account: { account: {
@ -256,6 +278,14 @@ export function lang() {
CHS:{ CHS:{
title: '更新日志', title: '更新日志',
timeline: [ timeline: [
{
label: '新建密码记录时支持生成密码',
tag:'功能更新',
content: [
'新建密码记录页的的密码输入框右侧支持打开生成密码页',
'2020-03-05'
]
},
{ {
label: '修复黑暗模式下主页分割线显示问题', label: '修复黑暗模式下主页分割线显示问题',
tag:'bug修复', tag:'bug修复',
@ -317,6 +347,14 @@ export function lang() {
EN:{ EN:{
title: 'Update Log', title: 'Update Log',
timeline: [ timeline: [
{
label: 'Support password generation when creating new password records',
tag:'Feature update',
content: [
'The right side of the password input box of the new password record page supports opening a generate password page',
'2020-03-05'
]
},
{ {
label: 'Fixed display of homepage split line in dark mode', label: 'Fixed display of homepage split line in dark mode',
tag:'Bug fix', tag:'Bug fix',

View File

@ -4,40 +4,92 @@
<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()"><md-icon>arrow_back</md-icon></md-button>
<h3 class="md-title" style="flex: 1">{{id_cache?lang.title[1]:lang.title[0]}}</h3> <h3 class="md-title" style="flex: 1">{{ id_cache ? lang.title[1] : lang.title[0] }}</h3>
</div> </div>
</md-app-toolbar> </md-app-toolbar>
<md-app-content> <md-app-content>
<div style="height: 54px;"></div> <div style="height: 54px;"></div>
<md-field :class="title_verify? '':'md-invalid'"> <md-field :class="title_verify ? '' : 'md-invalid'">
<label>{{lang.subheader[0]}}</label> <label>{{ lang.subheader[0] }}</label>
<md-input v-model="title" required></md-input> <md-input v-model="title" required></md-input>
<span class="md-error">{{lang.empty_error[0]}}</span> <span class="md-error">{{ lang.empty_error[0] }}</span>
</md-field> </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>
</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-title>生成密码</md-dialog-title>
<md-list>
<!-- 生成结果 -->
<md-subheader class="md-primary">{{lang.generator.subheader[0]}}</md-subheader>
<md-list-item>
<p>{{password ? password : lang.generator.code_res_empty}}</p>
</md-list-item>
<!-- settings -->
<md-subheader class="md-primary">{{lang.generator.subheader[1]}}</md-subheader>
<!-- 长度设置 -->
<md-list-item>
<md-field>
<label for="expired_time">{{lang.generator.length_setter.label}}</label>
<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="12">{{lang.generator.length_setter.options[1]}}</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="32">{{lang.generator.length_setter.options[4]}}</md-option>
</md-select>
</md-field>
</md-list-item>
<!-- 大写字母 -->
<md-list-item>
<span class="md-list-item-text">{{lang.generator.settings[0]}}</span>
<md-switch v-model="have_upper" class="md-primary"></md-switch>
</md-list-item>
<!-- 小写字母 -->
<md-list-item>
<span class="md-list-item-text">{{lang.generator.settings[1]}}</span>
<md-switch v-model="have_lower" class="md-primary"></md-switch>
</md-list-item>
<!-- 数字 -->
<md-list-item>
<span class="md-list-item-text">{{lang.generator.settings[2]}}</span>
<md-switch v-model="have_num" class="md-primary"></md-switch>
</md-list-item>
<!-- 符号 -->
<md-list-item>
<span class="md-list-item-text">{{lang.generator.settings[3]}}</span>
<md-switch v-model="have_symbol" class="md-primary"></md-switch>
</md-list-item>
</md-list>
<md-dialog-actions>
<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-dialog-actions>
</md-dialog>
</md-app-content> </md-app-content>
</md-app> </md-app>
</div> </div>
@ -47,9 +99,9 @@
// @ 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 { encrypt, decrypt, encryptMainCode, decryptMainCode } from '@/utils/aes.js';
import { lang } from '@/utils/language.js' import { lang } from '@/utils/language.js';
import { setHtmlFontSize } from '@/utils/px2rem.js' import { setHtmlFontSize } from '@/utils/px2rem.js';
import { generatePassword } from '@/utils/generator.js'
export default { export default {
name: 'Add', name: 'Add',
data() { data() {
@ -61,11 +113,22 @@ export default {
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,
//
have_upper: true,
//
have_lower: true,
//
have_num:true,
//
have_symbol: false,
//
code_length: 12,
}; };
}, },
computed: { computed: {
@ -91,19 +154,19 @@ export default {
if (now - this.row_pwd.create_time < this.settings.expired_time) { if (now - this.row_pwd.create_time < this.settings.expired_time) {
// //
// //
this.initLanguage() this.initLanguage();
if (this.$route.params.modify_content) { if (this.$route.params.modify_content) {
// //
let content = this.$route.params.modify_content let content = this.$route.params.modify_content;
this.title = content.title this.title = content.title;
this.user_name = content.user_name this.user_name = content.user_name;
this.password = content.password this.password = content.password;
this.node = content.node this.node = content.node;
this.web_address = content.web_address this.web_address = content.web_address;
this.id_cache = content.id this.id_cache = content.id;
this.open_count_cache = content.open_count this.open_count_cache = content.open_count;
} }
return return;
} else { } else {
// //
this.turnToHome('密码超时'); this.turnToHome('密码超时');
@ -113,92 +176,92 @@ export default {
this.turnToHome('无密码'); 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);
// //
@ -206,46 +269,51 @@ export default {
// 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()) : (random = random.toString());
// //
let id = time.toString() + random let id = time.toString() + random;
return id return id;
} },
//
generateStart() {
this.password = generatePassword(this.code_length, this.have_lower, this.have_upper, this.have_num, this.have_symbol)
},
}, },
created() { created() {
this.lang = lang().add.CHS this.lang = lang().add.CHS;
console.log('临时语言系统加载完成') console.log('临时语言系统加载完成');
this.init() this.init();
}, },
mounted() { mounted() {
// //
@ -260,7 +328,7 @@ export default {
// `clientHeight` // `clientHeight`
clientHeight: function() { clientHeight: function() {
this.changeFixed(this.clientHeight); this.changeFixed(this.clientHeight);
}, }
}, },
beforeDestroy() {}, beforeDestroy() {},
components: {} components: {}