Base Login

This commit is contained in:
ThienPhamVan
2026-03-25 10:06:01 +07:00
commit 3a2e16cf19
81 changed files with 27983 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
<template>
<div>
<div class="has-background-light px-5 pt-4 pb-2">
<Caption v-bind="{ title: 'Thông tin cộng tác viên' }"></Caption>
<div class="columns is-multiline mx-0">
<div class="column is-2">
<div class="field">
<label class="label"> số</label>
<div class="control fs-16">
{{ `CT${reginfo.user}` }}
</div>
</div>
</div>
<div class="column is-5">
<div class="field">
<label class="label">Link</label>
<div class="control fs-16">
<a @click="openLink()">{{ reginfo.link }}</a>
<p class="mt-2 hyperlink has-text-primary">
<span class="material-symbols-outlined" @click="copyContent()">content_copy</span>
</p>
</div>
</div>
</div>
<div class="column is-3">
<label class="label">QR code</label>
<div class="field is-grouped">
<div class="control">
<img style="width: 80px" :src="`${$path()}static/files/${reginfo.qrcode}`" />
</div>
<div class="control">
<p class="hyperlink has-text-primary">
<span class="material-symbols-outlined" @click="download()">download</span>
</p>
</div>
</div>
</div>
<div class="column is-2">
<div class="field">
<label class="label">Số </label>
<div class="control fs-16">
<span class="has-text-danger">{{ $numtoString(reginfo.balance) }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="mt-5" v-if="reginfo.status__code === 'wait'">
<p class="fs-16 has-text-primary">
Bạn đã đăng thành công. Vui lòng chờ phản hồi từ {{ company.name }}. Xin cảm ơn.
</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
company: this.$companyInfo(),
};
},
props: ['reginfo'],
methods: {
copyContent() {
this.$copyToClipboard(this.reginfo.link);
},
openLink() {
window.location.href = this.reginfo.link;
},
async download() {
let ulr = `${this.$path()}download?type=file&name=${this.reginfo.qrcode}`;
let response = await fetch(ulr);
const blob = await response.blob();
const urlDownload = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = urlDownload;
link.setAttribute('download', this.reginfo.qrcode);
link.click();
link.remove();
},
},
};
</script>

View File

@@ -0,0 +1,339 @@
<template>
<div v-if="record">
<Caption class="pt-1 pb-4" v-bind="{title: 'From đăng ký cộng tác viên', size: 20, type: 'has-text-black'}"></Caption>
<div class="has-background-light px-5 pt-4 pb-5">
<Caption v-bind="{title: 'Thông tin cá nhân'}"></Caption>
<div class="columns is-multiline mx-0 mt-3">
<div class="column is-4">
<div class="field">
<label class="label">Họ tên<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.fullname">
</div>
<p class="help is-danger" v-if="errors.fullname">{{errors.fullname}}</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Điện thoại<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.phone">
</div>
<p class="help is-danger" v-if="errors.phone">{{ errors.phone }}</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Ngày sinh<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<b-datepicker
locale="en-GB"
v-model="record._dob">
</b-datepicker>
</div>
<p class="help is-danger" v-if="errors.dob">{{ errors.dob }}</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Giới tính<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<SearchBox v-bind="{api:'sex', field:'name', column:['name'], first:true, optionid:record.sex}"
@option="selected('_sex', $event)"></SearchBox>
</div>
<p class="help is-danger" v-if="errors.sex">{{ errors.sex }}</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Tỉnh / thành phố<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<b-autocomplete
icon-right="magnify"
v-model="province"
placeholder=""
:keep-first=true
:open-on-focus=true
:data="provinces"
field="province_name"
@select="option => changeProvince(option)">
</b-autocomplete>
</div>
<p class="help is-danger" v-if="errors.province">{{errors.province}}</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Quận / huyện<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<b-autocomplete
icon-right="magnify"
v-model="district"
placeholder=""
:keep-first=true
:open-on-focus=true
:data="districts"
field="district_name"
@select="option => changeDistrict(option)">
</b-autocomplete>
</div>
<p class="help is-danger" v-if="errors.province">{{errors.district}}</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Phường / <b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<b-autocomplete
icon-right="magnify"
v-model="commune"
placeholder=""
:keep-first=true
:open-on-focus=true
:data="communes"
field="commune_name"
@select="option => selectCommune = option">
</b-autocomplete>
</div>
<p class="help is-danger" v-if="errors.commune">{{errors.commune}}</p>
</div>
</div>
<div class="column is-8">
<div class="field">
<label class="label">Địa chỉ<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.address">
</div>
<p class="help is-danger" v-if="errors.address">{{errors.address}}</p>
</div>
</div>
<div class="column is-12">
<div class="field">
<label class="label">Giới thiệu về bạn</label>
<div class="control">
<textarea class="textarea" v-model="note" placeholder="Hãy cho chúng tôi biết đôi nét về nghề nghiệp, kinh nghiệm tham gia thị trường, nơi làm việc của bạn. Thông tin này giúp chúng tôi hiểu về bạn từ đó hõ trợ được tốt hơn" rows="2"></textarea>
</div>
<p class="help is-danger" v-if="errors.address">{{errors.address}}</p>
</div>
</div>
</div>
</div>
<div class="has-background-light mt-5 px-5 pt-4 pb-5">
<Caption v-bind="{title: 'Giấy tờ tùy thân'}"></Caption>
<div class="columns is-multiline mx-0 mt-3">
<div class="column is-4">
<div class="field">
<label class="label">Số CMT / CC công dân<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.legal_id">
</div>
<p class="help is-danger" v-if="errors.legal_id">{{errors.legal_id}}</p>
</div>
</div>
<div class="column is-8">
<div class="field">
<label class="label">Nơi cấp<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.issue_place">
</div>
<p class="help is-danger" v-if="errors.issue_place">{{ errors.issue_place }}</p>
</div>
</div>
<div class="column is-12 pt-0">
<p class="mb-3 fs-13">Vui lòng tải lên mặt trước sau của CMT / CCCD (hình ảnh hoặc file scan). Thông tin này dùng để trả thưởng cho bạn</p>
<div class="field is-grouped is-grouped-multiline">
<div class="control is-expanded">
<b-upload v-model="file">
<a class="button is-findata is-rounded is-small" :class="loading? 'is-loading' : null">
<b-icon icon="mdi mdi-plus mr-1"></b-icon>
<span class="fs-14">Tải lên từ máy tính</span>
</a>
</b-upload>
</div>
<div class="control" v-for="(v,i) in files">
<div class="tags has-addons">
<a class="tag is-link">{{ v }}</a>
<a class="tag is-delete" @click="remove(i)"></a>
</div>
</div>
</div>
<p class="help is-danger" v-if="errors.files">{{ errors.files }}</p>
</div>
</div>
</div>
<div class="has-background-light mt-5 px-5 pt-4 pb-5">
<Caption v-bind="{title: 'Tài khoản ngân hàng'}"></Caption>
<div class="columns is-multiline mx-0 mt-3">
<div class="column is-3">
<div class="field">
<label class="label">Số tài khoản<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.bank_account">
</div>
<p class="help is-danger" v-if="errors.bank_account">{{errors.bank_account}}</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Tên tài khoản<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.account_name">
</div>
<p class="help is-danger" v-if="errors.account_name">{{ errors.account_name }}</p>
</div>
</div>
<div class="column is-5">
<div class="field">
<label class="label">Ngân hàng<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<SearchBox v-bind="{api:'bank', field:'name', column:['name'], first:true, optionid:record.bank}"
@option="selected('_bank', $event)"></SearchBox>
</div>
<p class="help is-danger" v-if="errors.bank">{{ errors.bank }}</p>
</div>
</div>
</div>
</div>
<div class="mt-5 pt-2 pb-5">
<button class="button is-primary" @click="register()">Đăng </button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
errors: {},
record: undefined,
provinces: this.$store.state.provinces || [],
districts: [],
communes: [],
selectProvince: undefined,
selectDistrict: undefined,
selectCommune: undefined,
selectLegal: undefined,
showmodal: undefined,
province: undefined,
district: undefined,
commune: undefined,
file: undefined,
datafile: undefined,
loading: undefined,
files: [],
note: undefined,
reginfo: undefined
}
},
async created() {
this.reginfo = await this.$getdata('affiliate', {user: this.login.id}, undefined, true)
if(this.reginfo) this.note = this.reginfo.note
this.record = await this.$getdata('user', {id: this.login.id}, undefined, true)
if(this.record.files) this.files = this.record.files
if(this.record.dob) this.$set(this.record, '_dob', new Date(this.record.dob))
if(!this.$store.state.provinces) {
this.provinces = await this.$getdata('province')
this.$store.commit('updateStore', {name: 'provinces', data: this.provinces})
}
if(this.record.location__province_code) {
this.selectProvince = this.$find(this.provinces, {province_code: this.record.location__province_code})
this.province = this.selectProvince.province_name
await this.getDistrict()
this.selectDistrict = this.$find(this.districts, {district_code: this.record.location__district_code})
this.district = this.selectDistrict.district_name
await this.getCommune()
this.selectCommune = this.$find(this.communes, {commune_code: this.record.location__commune_code})
this.commune = this.selectCommune.commune_name
}
},
computed: {
login: {
get: function() {return this.$store.state.login},
set: function(val) {this.$store.commit('updateLogin', {login: val})}
}
},
watch: {
file: function(newVal) {
if(!newVal) return
var file = this.$upload(newVal, 'file', this.login.id)
if(file.error) {
let info = {duration: 4000, type: 'is-danger', hasIcon: false, message: file.text}
this.$buefy.notification.open(info)
return
}
this.datafile = file
this.uploadImage(file)
}
},
methods: {
async uploadImage(file) {
this.loading = true
let rs = await this.$insertapi('upload', file.form)
this.loading = false
if(rs!=='error') this.files.push(rs.rows[0].file)
},
checkError() {
this.errors = {}
if(this.$empty(this.record.fullname)) this.errors.fullname = 'Họ tên không được bỏ trống'
if(this.$empty(this.record.phone)) this.errors.phone = 'Điện thoại không được bỏ trống'
if(this.$empty(this.record._sex)) this.errors.sex = 'Chưa chọn giới tính'
if(this.$empty(this.selectProvince)) this.errors.province = 'Chưa chọn Tỉnh / Thành phố'
if(this.$empty(this.selectDistrict)) this.errors.district = 'Chưa chọn Quận / Huyện'
if(this.$empty(this.selectCommune)) this.errors.commune = 'Chưa chọn Quận / Huyện'
if(this.$empty(this.record._dob)) this.errors.dob = 'Chưa nhập ngày sinh'
if(this.$empty(this.record.address)) this.errors.address = 'Địa chỉ không được bỏ trống'
if(this.$empty(this.record.legal_id)) this.errors.legal_id = 'Số CMT / CC công dân không được bỏ trống'
if(this.$empty(this.record.issue_place)) this.errors.issue_place = 'Nơi cấp không được bỏ trống'
if(this.files.length===0) this.errors.files = 'Bạn chưa tải lên chứng minh thư / căn cước công dân'
if(this.$empty(this.record.bank_account)) this.errors.bank_account = 'Số tài khoản không được bỏ trống'
if(this.$empty(this.record.account_name)) this.errors.account_name = 'Tên tài khoản không được bỏ trống'
if(this.$empty(this.record._bank)) this.errors.bank = 'Chưa chọn ngân hàng'
return Object.keys(this.errors).length>0
},
async register() {
if(this.checkError()) return
if(this.record._dob) this.record.dob = this.$dayjs(this.record._dob).format('YYYY-MM-DD')
if(this.record._sex) this.record.sex = this.record._sex.id
this.record.files = this.files
if(this.selectCommune) {
let found = await this.$getdata('location', {province_code: this.selectProvince.code, district_code: this.selectDistrict.district_code, commune_code: this.selectCommune.commune_code}, undefined, true)
if(found) this.record.location = found.id
}
let rs = await this.$updateapi('user', this.record)
let obj = {user: this.login.id, note: this.note, status: 1, bank_account: this.record.bank_account, account_name: this.record.account_name, bank: this.record._bank.id}
let found = this.$findapi('affiliate')
let rs1 = await this.$insertapi('affiliate', obj, found.params.values)
this.$emit('affiliate', rs1)
},
changeProvince(option) {
this.selectProvince = option
this.getDistrict()
this.selectDistrict = undefined
this.district = undefined
this.communes = []
this.selectCommune = undefined
this.commune = undefined
},
changeDistrict(option) {
this.selectDistrict = option
this.getCommune()
},
selected(attr, obj) {
this.record[attr] = obj
},
async getDistrict() {
if(!this.selectProvince) return
this.districts = await this.$getdata('district', {province_code: this.selectProvince.province_code})
},
async getCommune() {
if(!this.selectProvince) return
this.communes = await this.$getdata('commune', {province_code: this.selectProvince.province_code, district_code: this.selectDistrict.district_code})
},
openImage() {
this.showmodal = {component: 'common/Imagebox', title: 'Hình ảnh', width: '90%'}
},
remove(i) {
this.$delete(this.files, i)
}
}
}
</script>

View File

@@ -0,0 +1,46 @@
<template>
<div>
<div class="has-background-light px-5 pt-4 pb-5">
<Caption v-bind="{ title: 'Đăng ký cộng tác viên' }"></Caption>
<div class="columns is-multiline mx-0 mt-3">
<div class="column is-4">
<div class="field">
<label class="label">Họ tên<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
{{ reginfo.user__fullname }}
</div>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Ngày đăng <b class="ml-1 has-text-danger">*</b></label>
<div class="control">
{{ $dayjs(reginfo.create_time).format('DD/MM/YYYY') }}
</div>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Trạng thái<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<span class="tag is-success is-medium">{{ reginfo.status__name }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="mt-5" v-if="reginfo.status__code === 'wait'">
<p class="fs-16 has-text-primary">Bạn đã đăng thành công. Vui lòng chờ phản hồi từ {{ company.name }}. Xin cảm ơn.</p>
</div>
</div>
</template>
<script>
export default {
data() {
return{
company: this.$company(),
}
},
props: ['reginfo']
}
</script>