Files
system/components/user/CreateUser.vue
2026-02-25 16:18:22 +07:00

384 lines
15 KiB
Vue
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="px-3">
<div class="field is-horizontal">
<div class="field-body">
<div class="field">
<label class="label"
>{{ isVietnamese ? 'Tên đăng nhập' : 'Username' }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input class="input" type="text" placeholder="" v-model="username" />
</div>
<p class="help is-danger" v-if="errors.find((v) => v.name === 'username')">
{{ errors.find((v) => v.name === 'username').text }}
</p>
<p class="help is-primary" v-else-if="info">{{ info }}</p>
</div>
<div class="field" v-if="!dealer">
<label class="label"
>{{ isVietnamese ? 'Loại tài khoản' : 'Account type' }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<SearchBox
v-bind="{ api: 'usertype', field: 'name', column: ['name'], first: true, position: 'top' }"
@option="selected('_type', $event)"
></SearchBox>
</div>
<p class="help is-danger" v-if="errors.find((v) => v.name === 'type')">
{{ errors.find((v) => v.name === 'type').text }}
</p>
</div>
</div>
</div>
<div class="field is-horizontal mt-4">
<div class="field-body">
<div class="field">
<label class="label"
>{{ !dealer ? (isVietnamese ? 'Họ và tên' : 'Full name') : isVietnamese ? 'Tên tài khoản' : 'Dealer name'
}}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input class="input" type="text" placeholder="" v-model="fullname" />
</div>
<p class="help is-danger" v-if="errors.find((v) => v.name === 'fullname')">
{{ errors.find((v) => v.name === 'fullname').text }}
</p>
</div>
<div class="field">
<label class="label">{{ isVietnamese ? 'Email' : 'Email' }}<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="email" />
</div>
<p class="help is-danger" v-if="errors.find((v) => v.name === 'email')">
{{ errors.find((v) => v.name === 'email').text }}
</p>
</div>
</div>
</div>
<div class="field is-horizontal mt-4">
<div class="field-body">
<div class="field">
<label class="label">{{ isVietnamese ? 'Mật khẩu' : 'Password' }}<b class="ml-1 has-text-danger">*</b></label>
<div class="field has-addons">
<p class="control is-expanded">
<input
class="input"
:type="showpass ? 'text' : 'password'"
placeholder="At least 6 characters including letters and numbers."
v-model="password"
/>
</p>
<div class="control">
<a class="button" @click="showpass = !showpass">
<SvgIcon v-bind="{ name: 'eye-off.svg', type: 'dark', size: 22 }" v-if="showpass"></SvgIcon>
<SvgIcon v-bind="{ name: 'view.svg', type: 'dark', size: 22 }" v-else></SvgIcon>
</a>
</div>
</div>
<p class="help is-danger" v-if="errors.find((v) => v.name === 'password')">
{{ errors.find((v) => v.name === 'password').text }}
</p>
</div>
<div class="field">
<label class="label"
>{{ isVietnamese ? 'Nhập lại mật khẩu' : 'Retype password' }}<b class="ml-1 has-text-danger">*</b></label
>
<p class="control is-expanded">
<input class="input" :type="showpass ? 'text' : 'password'" placeholder="" v-model="retypePassword" />
</p>
</div>
<p class="help is-danger" v-if="errors.find((v) => v.name === 'retypePassword')">
{{ errors.find((v) => v.name === 'retypePassword').text }}
</p>
</div>
</div>
<div class="mt-5 pt-2">
<button
:class="`button is-primary has-text-white ${loading ? 'is-loading' : ''}`"
@click="createAccount()"
v-if="enable"
>
{{ isVietnamese ? 'Tạo tài khoản' : 'Create account' }}
</button>
</div>
</div>
</template>
<script>
import { useStore } from '~/stores/index';
export default {
setup() {
const store = useStore();
return { store };
},
props: ['pagename', 'row', 'api', 'dealer'],
data() {
return {
isVietnamese: this.$isVietnamese(),
fullname: undefined,
username: undefined,
email: undefined,
password: undefined,
retypePassword: undefined,
errors: [],
info: undefined,
showpass: true,
hash: undefined,
status: undefined,
user: undefined,
code: undefined,
option: undefined,
branch: [],
radio: undefined,
check: {},
branchOpt: undefined,
enable: true,
loading: false,
};
},
created() {
if (!this.row) return;
this.fullname = this.row.fullname;
this.email = this.row.email;
if (this.row.code) this.username = this.row.code.toLocaleLowerCase();
},
mounted() {
let pass = this.$id().toLocaleLowerCase();
this.password = pass;
this.retypePassword = pass;
window.addEventListener('keyup', (ev) =>
ev.key === 'Enter' && this.$route.name === 'signup' ? this.createAccount() : false,
);
},
computed: {
registermethod: {
get: function () {
return this.store.registermethod;
},
set: function (val) {
this.$store.commit('updateRegisterMethod', { registermethod: val });
},
},
authmethod: {
get: function () {
return this.store.authmethod;
},
set: function (val) {
this.$store.commit('updateAuthMethod', { authmethod: val });
},
},
authstatus: {
get: function () {
return this.store.authstatus;
},
set: function (val) {
this.$store.commit('updateAuthStatus', { authstatus: val });
},
},
usertype: {
get: function () {
return this.store.usertype;
},
set: function (val) {
this.$store.commit('updateUserType', { usertype: val });
},
},
dialog: {
get: function () {
return this.store['dialog'];
},
set: function (val) {
this.$store.commit('updateStore', { name: 'dialog', data: val });
},
},
},
methods: {
checkError() {
this.errors = [];
if (!this.$empty(this.fullname)) {
this.fullname = this.fullname.trim();
}
if (!this.$empty(this.username)) {
this.username = this.username.trim().toLowerCase();
}
if (this.$empty(this.fullname)) {
this.errors.push({ name: 'fullname', text: 'Họ và tên không được bỏ trống' });
} else if (this.fullname.length < 5) {
this.errors.push({ name: 'fullname', text: 'Họ và tên quá ngắn. Yêu cầu từ 5 kí tự trở nên' });
}
if (this.$empty(this.username)) {
this.errors.push({ name: 'username', text: 'Tài khoản không được bỏ trống' });
} else if (this.username !== this.username.replace(' ', '')) {
this.errors.push({ name: 'username', text: 'Tài khoản không được chứa khoảng trắng' });
} else if (this.username.length < 5) {
this.errors.push({ name: 'username', text: 'Tài khoản quá ngắn. Yêu cầu từ 5 kí tự trở nên' });
}
if (this.$empty(this.password)) {
this.errors.push({ name: 'password', text: 'Mật khẩu không được bỏ trống' });
} else if (this.password.length < 6) {
this.errors.push({ name: 'password', text: 'Mật khẩu gồm 6 kí tự trở nên bao gồm chữ và số ' });
} else if (!(/\d/.test(this.password) && /[a-zA-Z]/.test(this.password))) {
this.errors.push({ name: 'password', text: 'Mật khẩu gồm 6 kí tự trở nên bao gồm chữ và số ' });
}
if (this.$empty(this.retypePassword)) {
this.errors.push({ name: 'retypePassword', text: 'Nhắc lại mật khẩu không được bỏ trống' });
} else if (this.password !== this.retypePassword) {
this.errors.push({ name: 'retypePassword', text: 'Nhắc lại mật khẩu phải giống với mật khẩu đã nhập' });
}
if (!this.$empty(this.email)) {
this.email = this.email.trim();
if (this.$errEmail(this.email)) this.errors.push({ name: 'email', text: 'Email không hợp lệ.' });
} else {
this.errors.push({ name: 'email', text: 'Email không được bỏ trống.' });
}
if (this.$empty(this.option)) {
if (this.dealer) {
this.option = { id: 3 };
} else this.errors.push({ name: 'type', text: 'Chưa chọn loại tài khoản.' });
}
let opts = this.radio === 'all' ? 'all' : [];
if (opts.length === 0) {
for (const [key, value] of Object.entries(this.check)) {
if (value) opts.push(key);
}
}
return this.errors.length > 0 ? true : false;
},
async createAccount() {
this.loading = true;
if (this.checkError()) return (this.loading = false);
const response = await fetch(`${this.$getpath()}password/${this.password}/`);
if (!response.ok) {
throw new Error(`Response status: ${response.status}`);
}
this.hash = await response.json();
let data = await this.$getdata('user', { username: this.username }, undefined, true);
if (data) {
this.loading = false;
return this.errors.push({ name: 'username', text: 'Tài khoản đã tồn tại trong hệ thống' });
}
let found = this.$findapi('user');
data = {
fullname: this.fullname,
username: this.username,
phone: this.$empty(this.phone) ? undefined : this.phone,
password: this.hash,
type: this.option.id,
register_method: 1,
auth_status: 2,
auth_method: 1,
email: this.email,
};
this.user = await this.$insertrow('user', data, found.params.values, this.pagename);
if (this.user === 'error') return (this.loading = false);
if (this.row) {
let copy = this.$copy(this.row);
copy.user = this.user.id;
await this.$updaterow(this.api, copy, found.params.values, this.pagename);
} else {
let app = await this.$getdata('apps', { code: 'application' }, undefined, false);
let obj = { user: this.user.id, apps: app[0]?.id || null };
await this.$insertapi('userapps', obj, undefined, false);
//send email
if (this.email) {
let loginUrl = this.$mode === 'dev' ? 'https://dev.biz.utopia.com.vn/' : 'https://biz.utopia.com.vn/';
await this.templateEmail(loginUrl);
}
}
if (this.dealer) {
let copy = this.$copy(this.row);
copy.user = this.user.id;
await this.$updaterow('dealer', copy, null, this.pagename);
let app = await this.$getdata('apps', { code: 'dealer' }, undefined, false);
let obj = { user: this.user.id, apps: app[0]?.id || null };
await this.$insertapi('userapps', obj, undefined, false);
let loginUrl = this.$mode === 'dev' ? 'https://dev.dealer.utopia.com.vn/' : 'https://dealer.utopia.com.vn/';
await this.templateEmail(loginUrl);
}
this.loading = false;
this.$dialog('Tạo tài khoản thành công.', 'Thành công', 'Success', 10);
this.$emit('close');
},
async templateEmail(loginUrl) {
let content = `
<table width="100%" bgcolor="#f4f6f8" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding:30px 15px;">
<table width="600" cellpadding="0" cellspacing="0" border="0"
style="background:#ffffff; font-family:Arial, Helvetica, sans-serif; color:#333333; border-collapse:collapse;">
<tr>
<td style="padding:30px 25px; font-size:15px; line-height:1.6;">
<p style="margin:0 0 15px 0;">
Xin chào <strong>${this.fullname}</strong>,
</p>
<p style="margin:0 0 15px 0;">
Tài khoản đăng nhập của bạn đã được khởi tạo thành công và sẵn sàng sử dụng.
</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="margin:15px 0;">
<tr>
<td width="120" style="padding:6px 0;"><strong>Username:</strong></td>
<td style="padding:6px 0;">${this.username}</td>
</tr>
<tr>
<td style="padding:6px 0;"><strong>Password:</strong></td>
<td style="padding:6px 0;">${this.password}</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0" align="center" style="margin:25px auto;">
<tr>
<td align="center" bgcolor="#2f6fed" style="border-radius:4px;">
<a href="${loginUrl}"
target="_blank"
style="display:inline-block;
padding:12px 28px;
font-size:15px;
color:#ffffff;
text-decoration:none;
font-weight:bold;">
Đăng nhập ngay
</a>
</td>
</tr>
</table>
<p style="margin:25px 0 0 0;">
Trân trọng,<br/>
<strong>Đội ngũ Utopia</strong>
</p>
</td>
</tr>
<tr>
<td align="center"
style="padding:20px; font-size:12px; color:#777777; border-top:1px solid #eeeeee;">
© ${new Date().getFullYear()} Utopia Villas & Resort. All rights reserved.<br/>
Đây là email tự động, vui lòng không phản hồi email này.
</td>
</tr>
</table>
</td>
</tr>
</table>
`;
let info = {
subject: this.dealer
? `${this.$mode === 'dev' ? '[DEV] ' : ''}Thông báo khởi tạo tài khoản Cổng thông tin Đại lý Utopia`
: `${this.$mode === 'dev' ? '[DEV] ' : ''}Thông báo khởi tạo tài khoản Cổng thông tin Chủ đầu tư Utopia`,
to: this.email,
sender: 1,
content: content,
};
await this.$insertapi('sendemail', info, undefined, false);
},
selected(attr, obj) {
this.option = obj;
},
doCheck(v) {
this.$set(this.check, v.code, this.check[v.code] ? false : true);
},
},
};
</script>