chore: install prettier

This commit is contained in:
Viet An
2026-05-04 15:22:27 +07:00
parent 93d29ca7d8
commit bd58e2b847
267 changed files with 22950 additions and 13581 deletions

View File

@@ -1,175 +1,279 @@
<template>
<div v-if="record">
<div class="columns is-multiline mx-0">
<div :class="`column is-3 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{findLang('code')}}<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input class="input has-text-black" disabled type="text" placeholder="" v-model="record.code">
</div>
<p class="help is-danger" v-if="errors.code">{{ errors.code }}</p>
</div>
</div>
<div class="columns is-multiline mx-0">
<div :class="`column is-3 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{ findLang("code") }}<b class="ml-1 has-text-danger">*</b></label>
<div class="control">
<input
class="input has-text-black"
disabled
type="text"
placeholder=""
v-model="record.code"
/>
</div>
<p
class="help is-danger"
v-if="errors.code"
>
{{ errors.code }}
</p>
</div>
</div>
<div :class="`column is-6 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Tên công ty<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 :class="`column is-6 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Tên công ty<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-3 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{ findLang("shortname") }}</label>
<div class="control">
<input
class="input"
type="text"
placeholder=""
v-model="record.shortname"
/>
</div>
<p
class="help is-danger"
v-if="errors.shortname"
>
{{ errors.shortname }}
</p>
</div>
</div>
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{ findLang("taxcode") }}</label>
<div class="control">
<input
class="input"
type="text"
placeholder=""
v-model="record.legal_code"
/>
</div>
<p
class="help is-danger"
v-if="errors.legal_code"
>
{{ errors.legal_code }}
</p>
</div>
</div>
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Điện thoại</label>
<div class="control">
<InputPhone
v-bind="{ record: record, attr: 'phone', placeholder: '' }"
@phone="selected('phone', $event)"
></InputPhone>
</div>
<p
class="help is-danger"
v-if="errors.phone"
>
{{ errors.phone }}
<a
v-if="existedCustomer"
@click="showCustomer()"
>Chi tiết</a
>
</p>
</div>
</div>
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Email</label>
<div class="control">
<InputEmail
v-bind="{ record: record, attr: 'email', placeholder: '' }"
@email="selected('email', $event)"
></InputEmail>
</div>
<p
class="help is-danger"
v-if="errors.email"
>
{{ errors.email }}
</p>
</div>
</div>
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Website</label>
<div class="control">
<input
class="input"
type="text"
placeholder=""
v-model="record.website"
/>
</div>
</div>
</div>
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{ findLang("country") }}</label>
<div class="control">
<SearchBox
v-bind="{
vdata: store.country,
field: 'name',
column: ['name'],
first: true,
optionid: record.country,
position: 'is-top-left',
}"
@option="selected('_country', $event)"
></SearchBox>
</div>
</div>
</div>
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{ findLang("province") }}</label>
<div class="control">
<input
class="input"
type="text"
placeholder=""
v-model="record.province"
/>
</div>
</div>
</div>
<div :class="`column is-12 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{ findLang("address") }}</label>
<div class="control">
<input
class="input"
type="text"
placeholder=""
v-model="record.address"
/>
</div>
<p
class="help is-danger"
v-if="errors.address"
></p>
</div>
</div>
</div>
<div :class="`column is-3 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{findLang('shortname')}}</label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.shortname">
</div>
<p class="help is-danger" v-if="errors.shortname">{{errors.shortname}}</p>
</div>
<div class="mt-2">
<button
class="button is-primary has-text-white"
@click="update()"
>
{{ findLang("save") }}
</button>
</div>
<div :class="`column is-4 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{findLang('taxcode')}}</label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.legal_code">
<Modal
@close="showmodal = undefined"
v-bind="showmodal"
v-if="showmodal"
></Modal>
</div>
<p class="help is-danger" v-if="errors.legal_code">{{errors.legal_code}}</p>
</div>
</div>
<div :class="`column is-4 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Điện thoại</label>
<div class="control">
<InputPhone v-bind="{record: record, attr: 'phone', placeholder: ''}" @phone="selected('phone', $event)"></InputPhone>
</div>
<p class="help is-danger" v-if="errors.phone">{{ errors.phone }}
<a v-if="existedCustomer" @click="showCustomer()">Chi tiết</a>
</p>
</div>
</div>
<div :class="`column is-4 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Email</label>
<div class="control">
<InputEmail v-bind="{record: record, attr: 'email', placeholder: ''}" @email="selected('email', $event)"></InputEmail>
</div>
<p class="help is-danger" v-if="errors.email">{{ errors.email }}</p>
</div>
</div>
<div :class="`column is-4 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">Website</label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.website">
</div>
</div>
</div>
<div :class="`column is-4 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{findLang('country')}}</label>
<div class="control">
<SearchBox v-bind="{vdata: store.country, field:'name', column:['name'], first:true, optionid: record.country, position: 'is-top-left'}"
@option="selected('_country', $event)"></SearchBox>
</div>
</div>
</div>
<div :class="`column is-4 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{findLang('province')}}</label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.province">
</div>
</div>
</div>
<div :class="`column is-12 ${viewport===1? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{findLang('address')}}</label>
<div class="control">
<input class="input" type="text" placeholder="" v-model="record.address">
</div>
<p class="help is-danger" v-if="errors.address"></p>
</div>
</div>
</div>
<div class="mt-2">
<button class="button is-primary has-text-white" @click="update()">{{ findLang('save') }}</button>
</div>
<Modal @close="showmodal=undefined" v-bind="showmodal" v-if="showmodal"></Modal>
</div>
</template>
<script setup>
import InputPhone from '~/components/common/InputPhone'
import InputEmail from '~/components/common/InputEmail'
import SearchBox from '~/components/SearchBox'
import { useStore } from '@/stores/index'
var props = defineProps({
pagename: String,
row: Object
})
const store = useStore()
const { $find, $getdata, $updateapi, $insertapi, $findapi, $getapi, $empty, $errPhone, $resetNull, $snackbar } = useNuxtApp()
const emit = defineEmits(['update', 'dataevent'])
var viewport = store.viewport
var errors = ref({})
var record = ref()
var showmodal = undefined
var existedCustomer = undefined
async function initData() {
if(props.row) {
let conn = $findapi('company')
conn.params.filter = {id: props.row.company || props.row.customer__company || props.row.id}
let rs = await $getapi([conn])
let found = $find(rs, {name: 'company'})
if(found.data.rows.length>0) record.value = found.data.rows[0]
} else {
record.value = {}
import InputPhone from "~/components/common/InputPhone";
import InputEmail from "~/components/common/InputEmail";
import SearchBox from "~/components/SearchBox";
import { useStore } from "@/stores/index";
var props = defineProps({
pagename: String,
row: Object,
});
const store = useStore();
const { $find, $getdata, $updateapi, $insertapi, $findapi, $getapi, $empty, $errPhone, $resetNull, $snackbar } =
useNuxtApp();
const emit = defineEmits(["update", "dataevent"]);
var viewport = store.viewport;
var errors = ref({});
var record = ref();
var showmodal = undefined;
var existedCustomer = undefined;
async function initData() {
if (props.row) {
let conn = $findapi("company");
conn.params.filter = {
id: props.row.company || props.row.customer__company || props.row.id,
};
let rs = await $getapi([conn]);
let found = $find(rs, { name: "company" });
if (found.data.rows.length > 0) record.value = found.data.rows[0];
} else {
record.value = {};
}
}
function findLang(code) {
let found = $find(store.common, { code: code });
return found ? found[store.lang] : "";
}
function showCustomer() {
showmodal.value = {
component: "customer/CustomerView",
width: "60%",
height: "600px",
title: "Khách hàng",
vbind: { row: existedCustomer },
};
}
function selected(attr, obj) {
record.value[attr] = obj;
}
function checkError() {
existedCustomer = undefined;
errors.value = {};
if ($empty(record.value.fullname)) errors.value.fullname = "Họ tên không được bỏ trống";
if (record.value.phone) {
let text = $errPhone(record.value.phone);
if (text) errors.value.phone = text;
}
return Object.keys(errors.value).length > 0;
}
async function update() {
if (checkError()) return;
if (!record.value.id) {
if (record.value.phone) record.value.phone = record.value.phone.trim();
let obj = await $getdata("company", { phone: record.value.phone }, undefined, true);
if (obj) {
existedCustomer = obj;
errors.phone = "Số điện thoại đã tồn tại trong hệ thống.";
}
}
function findLang(code) {
let found = $find(store.common, {code: code})
return found? found[store.lang] : ''
}
function showCustomer() {
showmodal.value = {component: 'customer/CustomerView', width: '60%', height: '600px', title: 'Khách hàng', vbind: {row: existedCustomer}}
}
function selected(attr, obj) {
record.value[attr] = obj
}
function checkError() {
existedCustomer = undefined
errors.value = {}
if($empty(record.value.fullname)) errors.value.fullname = 'Họ tên không được bỏ trống'
if(record.value.phone) {
let text = $errPhone(record.value.phone)
if(text) errors.value.phone = text
}
return Object.keys(errors.value).length>0
}
async function update() {
if(checkError()) return
if(!record.value.id) {
if(record.value.phone) record.value.phone = record.value.phone.trim()
let obj = await $getdata('company', {phone: record.value.phone}, undefined, true)
if(obj) {
existedCustomer = obj
errors.phone = 'Số điện thoại đã tồn tại trong hệ thống.'
}
}
record.value = $resetNull(record.value)
if(record.value._country) record.value.country = record.value._country.id
if(!record.value.creator) record.value.creator = store.login.id
record.value.updater = store.login.id
record.update_time = new Date()
let rs = record.value.id? await $updateapi('company', record.value)
: await $insertapi('company', record.value)
if(rs==='error') return
if(!record.value.id) $snackbar(`Khách hàng đã được khởi tạo với mã <b>${rs.code}</b>`, 'Thành công', 'Success')
record.value.id = rs.id
let ele = await $getdata('company', {id:rs.id}, null, true)
emit('update', ele)
emit('modalevent', {name: 'dataevent', data: ele})
}
initData()
</script>
record.value = $resetNull(record.value);
if (record.value._country) record.value.country = record.value._country.id;
if (!record.value.creator) record.value.creator = store.login.id;
record.value.updater = store.login.id;
record.update_time = new Date();
let rs = record.value.id ? await $updateapi("company", record.value) : await $insertapi("company", record.value);
if (rs === "error") return;
if (!record.value.id) $snackbar(`Khách hàng đã được khởi tạo với mã <b>${rs.code}</b>`, "Thành công", "Success");
record.value.id = rs.id;
let ele = await $getdata("company", { id: rs.id }, null, true);
emit("update", ele);
emit("modalevent", { name: "dataevent", data: ele });
}
initData();
</script>

View File

@@ -10,14 +10,21 @@
v-for="(v, i) in tabs"
:key="i"
:class="['is-clickable p-3', i !== 0 && 'mt-2', getStyle(v)]"
style="width: 130px; border-radius: 4px;"
style="width: 130px; border-radius: 4px"
@click="changeTab(v)"
>
{{ isVietnamese ? v.name : v.en }}
</div>
</template>
<div v-else class="field is-grouped is-grouped-multiline">
<div class="control" v-for="(v, i) in tabs" @click="changeTab(v)">
<div
v-else
class="field is-grouped is-grouped-multiline"
>
<div
class="control"
v-for="(v, i) in tabs"
@click="changeTab(v)"
>
<div style="width: 130px">
<div :class="`py-3 px-3 ${getStyle(v)}`">
{{ isVietnamese ? v.name : v.en }}
@@ -54,7 +61,11 @@
</div>
</div>
<Modal @close="handleModalClose" v-bind="showmodal" v-if="showmodal"></Modal>
<Modal
@close="handleModalClose"
v-bind="showmodal"
v-if="showmodal"
></Modal>
</template>
<script setup>
import { computed, ref } from "vue";
@@ -99,11 +110,7 @@ function getStyle(v) {
function changeTab(v) {
if (tab.value === v.code) return;
if (!record)
return $dialog(
"Vui lòng <b>lưu dữ liệu</b> trước khi chuyển sang mục tiếp theo",
"Thông báo"
);
if (!record) return $dialog("Vui lòng <b>lưu dữ liệu</b> trước khi chuyển sang mục tiếp theo", "Thông báo");
tab.value = v.code;
}
@@ -115,7 +122,7 @@ function update(v) {
record = {
...v,
label: `${v.code} / ${v.fullname} / ${v.phone || ""}`,
}
};
emit("modalevent", { name: "dataevent", data: record });
if (!props.isEditMode) emit("close");
}
@@ -123,8 +130,7 @@ function update(v) {
<style scoped>
.title {
font-family: "Segoe UI", "Roboto", "Helvetica Neue", Helvetica, Arial,
sans-serif !important;
font-family: "Segoe UI", "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif !important;
}
.button.is-large.is-fullwidth:hover {
color: white !important;

View File

@@ -4,8 +4,7 @@
<div :class="`column is-2 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("custcode")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("custcode")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input
@@ -15,19 +14,30 @@
placeholder=""
/>
</div>
<p class="help is-danger" v-if="errors.code">{{ errors.code }}</p>
<p
class="help is-danger"
v-if="errors.code"
>
{{ errors.code }}
</p>
</div>
</div>
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("name")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("name")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input class="input" type="text" placeholder="" />
<input
class="input"
type="text"
placeholder=""
/>
</div>
<p class="help is-danger" v-if="errors.fullname">
<p
class="help is-danger"
v-if="errors.fullname"
>
{{ errors.fullname }}
</p>
</div>
@@ -35,8 +45,7 @@
<div :class="`column is-3 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("phone_number")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("phone_number")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<InputPhone
@@ -45,7 +54,10 @@
>
</InputPhone>
</div>
<p class="help is-danger" v-if="errors.phone">
<p
class="help is-danger"
v-if="errors.phone"
>
{{ errors.phone }}
<a
class="has-text-primary"
@@ -66,14 +78,18 @@
>
</InputEmail>
</div>
<p class="help is-danger" v-if="errors.email">{{ errors.email }}</p>
<p
class="help is-danger"
v-if="errors.email"
>
{{ errors.email }}
</p>
</div>
</div>
<div :class="`column is-3 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("gender")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("gender")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<SearchBox
@@ -93,8 +109,7 @@
<div :class="`column is-3 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("birth_date")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("birth_date")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<Datepicker
@@ -103,14 +118,18 @@
>
</Datepicker>
</div>
<p class="help is-danger" v-if="errors.dob">{{ errors.dob }}</p>
<p
class="help is-danger"
v-if="errors.dob"
>
{{ errors.dob }}
</p>
</div>
</div>
<div :class="`column is-3 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("country")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("country")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<SearchBox
@@ -130,8 +149,7 @@
<div :class="`column is-3 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("province")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("province")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input
@@ -146,8 +164,7 @@
<div :class="`column is-3 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("district")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("district")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input
@@ -162,8 +179,7 @@
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("address")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("address")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input
@@ -173,14 +189,15 @@
v-model="record.address"
/>
</div>
<p class="help is-danger" v-if="errors.address"></p>
<p
class="help is-danger"
v-if="errors.address"
></p>
</div>
</div>
<div :class="`column is-5 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{
dataLang && findFieldName("company")[lang]
}}</label>
<label class="label">{{ dataLang && findFieldName("company")[lang] }}</label>
<div class="control">
<SearchBox
v-bind="{
@@ -201,8 +218,7 @@
<div :class="`column is-3 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("personal_id")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("personal_id")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<SearchBox
@@ -222,8 +238,7 @@
<div :class="`column is-3 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("idnum")[lang] }}
<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("idnum")[lang] }} <b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input
@@ -233,7 +248,10 @@
v-model="record.legal_code"
/>
</div>
<p class="help is-danger" v-if="errors.legal_code">
<p
class="help is-danger"
v-if="errors.legal_code"
>
{{ errors.legal_code }}
</p>
</div>
@@ -241,8 +259,7 @@
<div :class="`column is-2 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("issued_date")[lang] }}
<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("issued_date")[lang] }} <b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<Datepicker
@@ -255,7 +272,10 @@
@date="selected('issued_date', $event)"
></Datepicker>
</div>
<p class="help is-danger" v-if="errors.issued_date">
<p
class="help is-danger"
v-if="errors.issued_date"
>
{{ errors.issued_date }}
</p>
</div>
@@ -263,8 +283,7 @@
<div :class="`column is-4 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label"
>{{ dataLang && findFieldName("issued_place")[lang] }}
<b class="ml-1 has-text-danger">*</b></label
>{{ dataLang && findFieldName("issued_place")[lang] }} <b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input
@@ -274,7 +293,10 @@
v-model="record.issued_place"
/>
</div>
<p class="help is-danger" v-if="errors.issued_place"></p>
<p
class="help is-danger"
v-if="errors.issued_place"
></p>
</div>
</div>
<div :class="`column is-3 px-0 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
@@ -306,9 +328,7 @@
<div :class="`column px-0 is-6 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<div class="field">
<label class="label">{{
dataLang && findFieldName("note")[lang]
}}</label>
<label class="label">{{ dataLang && findFieldName("note")[lang] }}</label>
<div class="control">
<textarea
class="textarea"
@@ -317,7 +337,12 @@
rows="1"
></textarea>
</div>
<p class="help is-danger" v-if="errors.note">{{ errors.note }}</p>
<p
class="help is-danger"
v-if="errors.note"
>
{{ errors.note }}
</p>
</div>
</div>
</div>
@@ -330,11 +355,15 @@
}"
></Caption>
</div>
<div class="columns mb-0 mx-0" v-for="(v, i) in people">
<div
class="columns mb-0 mx-0"
v-for="(v, i) in people"
>
<div :class="`column is-7 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<label class="label" v-if="i === 0"
>{{ findFieldName("select")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
<label
class="label"
v-if="i === 0"
>{{ findFieldName("select")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<SearchBox
v-bind="{
@@ -351,12 +380,18 @@
@option="selectPeople($event, v, i)"
>
</SearchBox>
<p class="help is-danger" v-if="v.error">{{ v.error }}</p>
<p
class="help is-danger"
v-if="v.error"
>
{{ v.error }}
</p>
</div>
<div :class="`column is-3 ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<label class="label" v-if="i === 0"
>{{ findFieldName("relationship")[lang]
}}<b class="ml-1 has-text-danger">*</b></label
<label
class="label"
v-if="i === 0"
>{{ findFieldName("relationship")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<SearchBox
v-bind="{
@@ -374,23 +409,30 @@
</SearchBox>
</div>
<div :class="`column ${viewport === 1 ? 'px-0 pb-1' : ''}`">
<label class="label" v-if="i === 0"
<label
class="label"
v-if="i === 0"
>{{ findFieldName("addmore")[lang] }}...</label
>
<button class="button px-2 is-dark mr-3" @click="add()">
<SvgIcon
v-bind="{ name: 'add1.png', type: 'white', size: 20 }"
></SvgIcon>
<button
class="button px-2 is-dark mr-3"
@click="add()"
>
<SvgIcon v-bind="{ name: 'add1.png', type: 'white', size: 20 }"></SvgIcon>
</button>
<button class="button px-2 is-warning" @click="remove(v, i)">
<SvgIcon
v-bind="{ name: 'bin1.svg', type: 'white', size: 20 }"
></SvgIcon>
<button
class="button px-2 is-warning"
@click="remove(v, i)"
>
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'white', size: 20 }"></SvgIcon>
</button>
</div>
</div>
<div class="mt-2">
<button class="button is-primary has-text-white" @click="update()">
<button
class="button is-primary has-text-white"
@click="update()"
>
{{ store.lang === "en" ? "Save" : "Lưu lại" }}
</button>
</div>
@@ -410,17 +452,7 @@ import Datepicker from "~/components/datepicker/Datepicker";
import { useStore } from "@/stores/index";
const emit = defineEmits(["close", "update"]);
const nuxtApp = useNuxtApp();
const {
$getdata,
$updateapi,
$insertapi,
$empty,
$errPhone,
$resetNull,
$snackbar,
$copy,
$dayjs,
} = nuxtApp;
const { $getdata, $updateapi, $insertapi, $empty, $errPhone, $resetNull, $snackbar, $copy, $dayjs } = nuxtApp;
var props = defineProps({
pagename: String,
row: Object,
@@ -540,10 +572,7 @@ function showCustomer() {
}
const selected = (fieldName, value) => {
const finalValue =
value !== null && typeof value === "object"
? value.id || value.index
: value;
const finalValue = value !== null && typeof value === "object" ? value.id || value.index : value;
record.value[fieldName] = finalValue;
if (errors.value[fieldName]) {
@@ -566,9 +595,7 @@ function checkError() {
}
if ($empty(record.value.dob)) {
errors.value.dob = isVietnamese.value
? "Ngày sinh không được bỏ trống"
: "Date of birth cannot be empty";
errors.value.dob = isVietnamese.value ? "Ngày sinh không được bỏ trống" : "Date of birth cannot be empty";
} else {
if (record.value.dob > new Date()) {
errors.value.dob = isVietnamese.value
@@ -583,21 +610,15 @@ function checkError() {
}
if ($empty(record.value.legal_code)) {
errors.value.legal_code = isVietnamese.value
? "Mã số không được bỏ trống"
: "Legal code cannot be empty";
errors.value.legal_code = isVietnamese.value ? "Mã số không được bỏ trống" : "Legal code cannot be empty";
}
if ($empty(record.value.issued_date)) {
errors.value.issued_date = isVietnamese.value
? "Ngày cấp không được bỏ trống"
: "Date of issue cannot be empty";
errors.value.issued_date = isVietnamese.value ? "Ngày cấp không được bỏ trống" : "Date of issue cannot be empty";
}
if ($empty(record.value.issued_place)) {
errors.value.issued_place = isVietnamese.value
? "Nơi cấp không được bỏ trống"
: "Place of issue cannot be empty";
errors.value.issued_place = isVietnamese.value ? "Nơi cấp không được bỏ trống" : "Place of issue cannot be empty";
}
return Object.keys(errors.value).length > 0;
}
@@ -637,45 +658,26 @@ async function update() {
try {
if (record.value.phone) {
record.value.phone = record.value.phone.trim();
let phoneCheck = await $getdata(
"customer",
{ phone: record.value.phone },
undefined,
true
);
let phoneCheck = await $getdata("customer", { phone: record.value.phone }, undefined, true);
if (phoneCheck) {
existedCustomer = phoneCheck;
errors.value.phone = isVietnamese.value
? "Số điện thoại đã tồn tại."
: "Phone number already exists.";
errors.value.phone = isVietnamese.value ? "Số điện thoại đã tồn tại." : "Phone number already exists.";
return;
}
}
// Kiểm tra email
if (record.value.email && record.value.email.trim() !== "") {
let emailCheck = await $getdata(
"customer",
{ email: record.value.email.trim() },
undefined,
true
);
let emailCheck = await $getdata("customer", { email: record.value.email.trim() }, undefined, true);
if (emailCheck) {
errors.value.email = isVietnamese.value
? "Email đã tồn tại."
: "Email already exists.";
errors.value.email = isVietnamese.value ? "Email đã tồn tại." : "Email already exists.";
return;
}
}
// Kiểm tra legal_code
if (record.value.legal_code) {
let legalCheck = await $getdata(
"customer",
{ legal_code: record.value.legal_code },
undefined,
true
);
let legalCheck = await $getdata("customer", { legal_code: record.value.legal_code }, undefined, true);
if (legalCheck) {
errors.value.legal_code = isVietnamese.value
? "Số CMND/CCCD đã tồn tại."
@@ -714,34 +716,25 @@ async function update() {
return;
}
record.value.id = rs.id;
const customerData = await $getdata(
"customer",
{ id: rs.id },
undefined,
true
);
const customerData = await $getdata("customer", { id: rs.id }, undefined, true);
if (isNewCustomer) {
// link user=customer
await $getdata("linkusercustomer", undefined, { phone: rs.phone });
$snackbar(
`${
isVietnamese.value
? "Khách hàng đã được khởi tạo với mã"
: "Customer has been created with code"
isVietnamese.value ? "Khách hàng đã được khởi tạo với mã" : "Customer has been created with code"
} <b>${rs.code}</b>`,
"Thành công",
"Success"
"Success",
);
} else {
$snackbar(
`${
isVietnamese.value
? "Khách hàng đã được cập nhật với mã"
: "Customer has been updated with code"
isVietnamese.value ? "Khách hàng đã được cập nhật với mã" : "Customer has been updated with code"
} <b>${rs.code}</b>`,
"Thành công",
"Success"
"Success",
);
}
@@ -760,9 +753,7 @@ async function update() {
//Xử lý file uploads nếu có
if (record.value.image && record.value.image.length > 0) {
let arr = [];
record.value.image.map((v) =>
arr.push({ ref: record.value.id, file: v })
);
record.value.image.map((v) => arr.push({ ref: record.value.id, file: v }));
await $insertapi("customerfile", arr, undefined, false);
}
emit("update", customerData);

View File

@@ -1,5 +1,8 @@
<template>
<div v-if="!selectedCustomerType && isNewCustomer && !props.customerType" class="p-5">
<div
v-if="!selectedCustomerType && isNewCustomer && !props.customerType"
class="p-5"
>
<h3 class="title is-4 mb-5 has-text-centered">
{{ isVietnamese ? "Chọn loại khách hàng" : "Select Customer Type" }}
</h3>
@@ -7,8 +10,8 @@
<div class="column is-6">
<button
:disabled="!$getEditRights('edit', { code: 'individual', category: 'submenu' })"
class="button is-large is-fullwidth"
style="height: 120px"
class="button is-large is-fullwidth"
style="height: 120px"
@click="selectCustomerType(1)"
>
<div class="has-text-centered">
@@ -22,10 +25,10 @@
</button>
</div>
<div class="column is-6">
<button
<button
:disabled="!$getEditRights('edit', { code: 'org', category: 'submenu' })"
class="button is-large is-fullwidth"
style="height: 120px"
class="button is-large is-fullwidth"
style="height: 120px"
@click="selectCustomerType(2)"
>
<div class="has-text-centered">
@@ -46,28 +49,60 @@
<div class="columns is-multiline">
<div class="column is-4">
<div class="field">
<label class="label">{{ isIndividual ? "Họ và tên" : "Tên tổ chức" }}<b class="ml-1 has-text-danger">*</b></label>
<label class="label"
>{{ isIndividual ? "Họ và tên" : "Tên tổ chức" }}<b class="ml-1 has-text-danger">*</b></label
>
<div class="control">
<input class="input" type="text" v-model="record.fullname" />
<input
class="input"
type="text"
v-model="record.fullname"
/>
</div>
<p class="help is-danger" v-if="errors.fullname">{{ errors.fullname }}</p>
<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">{{ dataLang && findFieldName("phone_number")[lang] }}<b class="ml-1 has-text-danger">*</b></label>
<InputPhone v-bind="{ record: record, attr: 'phone' }" @phone="selected('phone', $event)"></InputPhone>
<p class="help is-danger" v-if="errors.phone">
<label class="label"
>{{ dataLang && findFieldName("phone_number")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<InputPhone
v-bind="{ record: record, attr: 'phone' }"
@phone="selected('phone', $event)"
></InputPhone>
<p
class="help is-danger"
v-if="errors.phone"
>
{{ errors.phone }}
<a class="has-text-primary" v-if="existedCustomer" @click="showCustomer()">Chi tiết</a>
<a
class="has-text-primary"
v-if="existedCustomer"
@click="showCustomer()"
>Chi tiết</a
>
</p>
</div>
</div>
<div class="column is-4">
<div class="field">
<label class="label">Email</label>
<InputEmail v-bind="{ record: record, attr: 'email' }" @email="selected('email', $event)"></InputEmail>
<p class="help is-danger" v-if="errors.email">{{ errors.email }}</p>
<InputEmail
v-bind="{ record: record, attr: 'email' }"
@email="selected('email', $event)"
></InputEmail>
<p
class="help is-danger"
v-if="errors.email"
>
{{ errors.email }}
</p>
</div>
</div>
</div>
@@ -75,28 +110,47 @@
<div class="column is-6">
<div class="field">
<label class="label">Địa chỉ liên hệ</label>
<input class="input" type="text" v-model="record.contact_address" />
<input
class="input"
type="text"
v-model="record.contact_address"
/>
</div>
</div>
<div class="column is-6">
<div class="field">
<label class="label">{{ isIndividual ? 'Địa chỉ thường trú' : 'Địa chỉ đăng ký' }}</label>
<input class="input" type="text" v-model="record.address" />
<label class="label">{{ isIndividual ? "Địa chỉ thường trú" : "Địa chỉ đăng ký" }}</label>
<input
class="input"
type="text"
v-model="record.address"
/>
</div>
</div>
</div>
<div v-if="isOrganization" class="columns is-multiline">
<div
v-if="isOrganization"
class="columns is-multiline"
>
<div class="column is-6">
<div class="field">
<label class="label">Tài khoản ngân hàng</label>
<input class="input" type="text" v-model="organizationData.bank_account" />
<input
class="input"
type="text"
v-model="organizationData.bank_account"
/>
</div>
</div>
<div class="column is-6">
<div class="field">
<label class="label">Tên ngân hàng</label>
<input class="input" type="text" v-model="organizationData.bank_name" />
<input
class="input"
type="text"
v-model="organizationData.bank_name"
/>
</div>
</div>
</div>
@@ -104,46 +158,117 @@
<div class="columns is-multiline">
<div class="column is-3">
<div class="field">
<label class="label">{{ isIndividual ? 'Giấy tờ tùy thân' : 'Giấy tờ' }}<b class="ml-1 has-text-danger">*</b></label>
<SearchBox v-bind="{ vdata: filteredLegalTypes, api: 'legaltype', field: isVietnamese ? 'name' : 'en', column: ['name', 'en'], first: true, optionid: record.legal_type }" @option="selected('legal_type', $event)"></SearchBox>
<label class="label"
>{{ isIndividual ? "Giấy tờ tùy thân" : "Giấy tờ" }}<b class="ml-1 has-text-danger">*</b></label
>
<SearchBox
v-bind="{
vdata: filteredLegalTypes,
api: 'legaltype',
field: isVietnamese ? 'name' : 'en',
column: ['name', 'en'],
first: true,
optionid: record.legal_type,
}"
@option="selected('legal_type', $event)"
></SearchBox>
</div>
</div>
<div class="column is-3">
<div class="field">
<label class="label">{{ dataLang && findFieldName("idnum")[lang] }}<b class="ml-1 has-text-danger">*</b></label>
<input class="input" type="text" v-model="record.legal_code" />
<p class="help is-danger" v-if="errors.legal_code">{{ errors.legal_code }}</p>
<label class="label"
>{{ dataLang && findFieldName("idnum")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<input
class="input"
type="text"
v-model="record.legal_code"
/>
<p
class="help is-danger"
v-if="errors.legal_code"
>
{{ errors.legal_code }}
</p>
</div>
</div>
<div class="column is-3">
<div class="field">
<label class="label">{{ dataLang && findFieldName("issued_date")[lang] }}<b class="ml-1 has-text-danger">*</b></label>
<Datepicker v-bind="{ record: record, attr: 'issued_date', maxdate: new Date() }" @date="selected('issued_date', $event)"></Datepicker>
<p class="help is-danger" v-if="errors.issued_date">{{ errors.issued_date }}</p>
<label class="label"
>{{ dataLang && findFieldName("issued_date")[lang] }}<b class="ml-1 has-text-danger">*</b></label
>
<Datepicker
v-bind="{
record: record,
attr: 'issued_date',
maxdate: new Date(),
}"
@date="selected('issued_date', $event)"
></Datepicker>
<p
class="help is-danger"
v-if="errors.issued_date"
>
{{ errors.issued_date }}
</p>
</div>
</div>
<div class="column is-3">
<div class="field">
<label class="label">{{ dataLang && findFieldName("issued_place")[lang] }}</label>
<SearchBox
v-bind="{ api: 'issuedplace', field: 'name', column: ['name'], first: true, position: 'is-bottom-right', optionid: record.issued_place,filter: {id__in: isIndividual ? [2, 3] : [4, 5] } }"
@option="selected('issued_place', $event)"></SearchBox>
v-bind="{
api: 'issuedplace',
field: 'name',
column: ['name'],
first: true,
position: 'is-bottom-right',
optionid: record.issued_place,
filter: { id__in: isIndividual ? [2, 3] : [4, 5] },
}"
@option="selected('issued_place', $event)"
></SearchBox>
</div>
</div>
</div>
<div class="columns is-multiline" v-if="isIndividual">
<div
class="columns is-multiline"
v-if="isIndividual"
>
<div class="column is-3">
<div class="field">
<label class="label">{{ dataLang && findFieldName("gender")[lang] }}</label>
<SearchBox v-bind="{ vdata: store.sex, api: 'sex', field: isVietnamese ? 'name' : 'en', column: ['name', 'en'], first: true, optionid: individualData.sex }" @option="selectedIndividual('sex', $event)"></SearchBox>
<SearchBox
v-bind="{
vdata: store.sex,
api: 'sex',
field: isVietnamese ? 'name' : 'en',
column: ['name', 'en'],
first: true,
optionid: individualData.sex,
}"
@option="selectedIndividual('sex', $event)"
></SearchBox>
</div>
</div>
</div>
<div class="column is-3">
<div class="field">
<label class="label">{{ dataLang && findFieldName("birth_date")[lang] }}</label>
<Datepicker v-bind="{ record: individualData, attr: 'dob', maxdate: new Date() }" @date="selectedIndividual('dob', $event)"></Datepicker>
<p class="help is-danger" v-if="errors.dob">{{ errors.dob }}</p>
<Datepicker
v-bind="{
record: individualData,
attr: 'dob',
maxdate: new Date(),
}"
@date="selectedIndividual('dob', $event)"
></Datepicker>
<p
class="help is-danger"
v-if="errors.dob"
>
{{ errors.dob }}
</p>
</div>
</div>
</div>
@@ -152,19 +277,33 @@
<div class="column is-12">
<div class="field">
<label class="label">{{ dataLang && findFieldName("note")[lang] }}</label>
<textarea class="textarea" v-model="record.note" rows="2"></textarea>
<textarea
class="textarea"
v-model="record.note"
rows="2"
></textarea>
</div>
</div>
</div>
<div class="mt-5 mb-4">
<h4 class="title is-6 has-text-warning">{{ isIndividual ? 'Người liên quan' : 'Người đại diện pháp luật' }}</h4>
<h4 class="title is-6 has-text-warning">
{{ isIndividual ? "Người liên quan" : "Người đại diện pháp luật" }}
</h4>
</div>
<div class="columns is-multiline mb-0 is-2" v-for="(v, i) in localPeople" :key="i">
<div
class="columns is-multiline mb-0 is-2"
v-for="(v, i) in localPeople"
:key="i"
>
<div class="column">
<label class="label" v-if="i === 0">{{ findFieldName("select")[lang] }}</label>
<SearchBox
v-bind="{
<label
class="label"
v-if="i === 0"
>{{ findFieldName("select")[lang] }}</label
>
<SearchBox
v-bind="{
api: 'people',
field: 'label',
column: ['code', 'fullname', 'phone'],
@@ -172,34 +311,54 @@
optionid: v.people,
position: 'is-top-left',
addon: peopleAddon,
viewaddon: peopleviewAddon
}"
@option="selectPeople($event, v, i)"></SearchBox>
viewaddon: peopleviewAddon,
}"
@option="selectPeople($event, v, i)"
></SearchBox>
</div>
<div class="column is-4">
<label class="label" v-if="i === 0">{{ isIndividual ? 'Quan hệ' : 'Chức vụ' }}</label>
<SearchBox
v-bind="{
<label
class="label"
v-if="i === 0"
>{{ isIndividual ? "Quan hệ" : "Chức vụ" }}</label
>
<SearchBox
v-bind="{
api: 'relation',
field: store.lang === 'en' ? 'en' : 'name',
column: ['code', 'name', 'en'],
first: true,
optionid: v.relation,
column: ['code', 'name', 'en'],
first: true,
optionid: v.relation,
position: 'is-top-left',
filter:{ id__in: isIndividual ? [1,2,3,4,5,6,7,8] : [9,10,11,12] }
}"
filter: {
id__in: isIndividual ? [1, 2, 3, 4, 5, 6, 7, 8] : [9, 10, 11, 12],
},
}"
@option="selectRelation($event, v, i)"
/>
</div>
<div class="column is-narrow">
<label class="label" v-if="i === 0">&nbsp;</label>
<div class="buttons is-gap-0.5 is-flex-wrap-nowrap are-small" style="height: 40px">
<button class="button is-dark" @click="add()">
<label
class="label"
v-if="i === 0"
>&nbsp;</label
>
<div
class="buttons is-gap-0.5 is-flex-wrap-nowrap are-small"
style="height: 40px"
>
<button
class="button is-dark"
@click="add()"
>
<span class="icon">
<SvgIcon v-bind="{ name: 'add4.svg', type: 'white', size: 20 }"></SvgIcon>
</span>
</button>
<button class="button is-dark" @click="remove(v, i)">
<button
class="button is-dark"
@click="remove(v, i)"
>
<span class="icon">
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'white', size: 20 }"></SvgIcon>
</span>
@@ -209,11 +368,25 @@
</div>
<div class="mt-5 buttons is-right">
<button class="button" @click="emit('close')">{{ isVietnamese ? 'Hủy' : 'Cancel' }}</button>
<button class="button is-primary" @click="update()">{{ isVietnamese ? 'Lưu lại' : 'Save' }}</button>
<button
class="button"
@click="emit('close')"
>
{{ isVietnamese ? "Hủy" : "Cancel" }}
</button>
<button
class="button is-primary"
@click="update()"
>
{{ isVietnamese ? "Lưu lại" : "Save" }}
</button>
</div>
<Modal @close="showmodal = undefined" v-bind="showmodal" v-if="showmodal"></Modal>
<Modal
@close="showmodal = undefined"
v-bind="showmodal"
v-if="showmodal"
></Modal>
</div>
</template>
</template>
@@ -226,7 +399,7 @@ import InputEmail from "~/components/common/InputEmail";
import SearchBox from "~/components/SearchBox";
import Datepicker from "~/components/datepicker/Datepicker";
import { useStore } from "~/stores/index";
import { isEqual, pick } from 'es-toolkit';
import { isEqual, pick } from "es-toolkit";
const emit = defineEmits(["close", "update", "modalevent"]);
const { $getdata, $patchapi, $insertapi, $deleteapi, $empty, $errPhone, $resetNull, $snackbar, $copy } = useNuxtApp();
@@ -260,21 +433,32 @@ const isOrganization = computed(() => selectedCustomerType.value === 2);
const filteredLegalTypes = computed(() => {
if (!store.legaltype) return [];
return isOrganization.value ? store.legaltype.filter(lt => lt.id === 4) : store.legaltype.filter(lt => lt.id !== 4);
return isOrganization.value
? store.legaltype.filter((lt) => lt.id === 4)
: store.legaltype.filter((lt) => lt.id !== 4);
});
const peopleAddon = {
const peopleAddon = {
component: "people/People",
width: "65%",
height: "500px",
title: store.lang === "en" ? "Related person" : "Người liên quan"
height: "500px",
title: store.lang === "en" ? "Related person" : "Người liên quan",
};
const peopleviewAddon = { ...peopleAddon };
function selectCustomerType(type) {
const typeNum = Number(type);
selectedCustomerType.value = typeNum;
record.value = { fullname: "", phone: "", email: "", country: 1, type: typeNum, legal_type: typeNum === 2 ? 4 : null, creator: store.login.id, updater: store.login.id };
record.value = {
fullname: "",
phone: "",
email: "",
country: 1,
type: typeNum,
legal_type: typeNum === 2 ? 4 : null,
creator: store.login.id,
updater: store.login.id,
};
if (typeNum === 1) {
individualData.value = { dob: null, sex: 1 };
organizationData.value = {};
@@ -287,40 +471,61 @@ function selectCustomerType(type) {
}
function findFieldName(code) {
return dataLang.value.find(item => item.code === code) || { vi: code, en: code };
return dataLang.value.find((item) => item.code === code) || { vi: code, en: code };
}
function showCustomer() {
showmodal.value = { component: "customer/CustomerView", width: "60%", height: "600px", title: "Khách hàng", vbind: { row: existedCustomer.value } };
showmodal.value = {
component: "customer/CustomerView",
width: "60%",
height: "600px",
title: "Khách hàng",
vbind: { row: existedCustomer.value },
};
}
const selected = (f, v) => { record.value[f] = (v && typeof v === 'object') ? v.id : v; if (errors.value[f]) delete errors.value[f]; };
const selectedIndividual = (f, v) => { individualData.value[f] = (v && typeof v === 'object') ? v.id : v; };
const selectedOrg = (f, v) => { organizationData.value[f] = (v && typeof v === 'object') ? v.id : v; };
const selectPeople = (opt, _v, i) => {
localPeople.value[i].people = opt.id;
const selected = (f, v) => {
record.value[f] = v && typeof v === "object" ? v.id : v;
if (errors.value[f]) delete errors.value[f];
};
const selectedIndividual = (f, v) => {
individualData.value[f] = v && typeof v === "object" ? v.id : v;
};
const selectedOrg = (f, v) => {
organizationData.value[f] = v && typeof v === "object" ? v.id : v;
};
const selectPeople = (opt, _v, i) => {
localPeople.value[i].people = opt.id;
};
const selectRelation = (opt, _v, i) => {
localPeople.value[i].relation = opt ? opt.id : null;
};
const selectRelation = (opt, _v, i) => { localPeople.value[i].relation = opt ? opt.id : null; };
const add = () => localPeople.value.push({});
const remove = (_v, i) => {
localPeople.value.splice(i, 1);
if (localPeople.value.length === 0) localPeople.value = [{}];
};
watch(people, (val) => {
localPeople.value = val.map(cp => pick(cp, ['id', 'people', 'relation']));
}, { deep: true })
watch(
people,
(val) => {
localPeople.value = val.map((cp) => pick(cp, ["id", "people", "relation"]));
},
{ deep: true },
);
function checkError() {
errors.value = {};
if ($empty(record.value.fullname)) errors.value.fullname = isVietnamese.value ? "Họ tên không được bỏ trống" : "Full name is required";
if ($empty(record.value.fullname))
errors.value.fullname = isVietnamese.value ? "Họ tên không được bỏ trống" : "Full name is required";
if ($empty(record.value.phone)) {
errors.value.phone = isVietnamese.value ? "Số điện thoại không được bỏ trống" : "Phone is required";
} else {
const text = $errPhone(record.value.phone);
if (text) errors.value.phone = text;
}
if ($empty(record.value.legal_code)) errors.value.legal_code = isVietnamese.value ? "Mã số không được bỏ trống" : "Legal code is required";
if ($empty(record.value.legal_code))
errors.value.legal_code = isVietnamese.value ? "Mã số không được bỏ trống" : "Legal code is required";
if ($empty(record.value.issued_date)) errors.value.issued_date = "Ngày cấp không được bỏ trống";
return Object.keys(errors.value).length > 0;
@@ -349,7 +554,10 @@ async function update() {
}
if (record.value.legal_code) {
const legalCheck = await $getdata("customer", { legal_code: record.value.legal_code }, undefined, true);
if (legalCheck) { errors.value.legal_code = "Số CMND/CCCD đã tồn tại."; return; }
if (legalCheck) {
errors.value.legal_code = "Số CMND/CCCD đã tồn tại.";
return;
}
}
}
@@ -358,7 +566,9 @@ async function update() {
customerData.updater = store.login.id;
customerData.update_time = new Date();
let res = isNewCustomer.value ? await $insertapi("customer", customerData, undefined, false) : await $patchapi("customer", customerData, undefined, false);
let res = isNewCustomer.value
? await $insertapi("customer", customerData, undefined, false)
: await $patchapi("customer", customerData, undefined, false);
if (!res || res === "error") return;
const customerId = res.id;
@@ -367,7 +577,8 @@ async function update() {
if (isIndividual.value) {
let indPayload = $resetNull({ ...individualData.value });
indPayload.customer = customerId;
if (individualData.value.id) await $patchapi("individual", { ...indPayload, id: individualData.value.id }, undefined, false);
if (individualData.value.id)
await $patchapi("individual", { ...indPayload, id: individualData.value.id }, undefined, false);
else await $insertapi("individual", indPayload, undefined, false);
} else if (isOrganization.value) {
let orgPayload = $resetNull({ ...organizationData.value });
@@ -393,22 +604,22 @@ async function update() {
commonPayload = { organization: organizationId };
}
const validLocalPeople = localPeople.value.filter(lp => lp.people && lp.relation).map(lp => toRaw(lp));
const peopleKeys = people.value.map(p => pick(p, ['id', 'people', 'relation']));
const validLocalPeople = localPeople.value.filter((lp) => lp.people && lp.relation).map((lp) => toRaw(lp));
const peopleKeys = people.value.map((p) => pick(p, ["id", "people", "relation"]));
// 1. check existing ids, if people or relation changes -> patch
const existingLocalPeople = validLocalPeople.filter(cp => Boolean(cp.id));
existingLocalPeople.forEach(lp => {
const match = peopleKeys.find(p => isEqual(p, lp));
const payload = { ...lp, ...commonPayload }
const existingLocalPeople = validLocalPeople.filter((cp) => Boolean(cp.id));
existingLocalPeople.forEach((lp) => {
const match = peopleKeys.find((p) => isEqual(p, lp));
const payload = { ...lp, ...commonPayload };
if (!match) {
$patchapi(apiName, payload);
}
});
// 2. if localPeople has and people doesn't -> insert
validLocalPeople.forEach(lp => {
validLocalPeople.forEach((lp) => {
if (!lp.id) {
const payload = { ...lp, ...commonPayload };
$insertapi(apiName, payload);
@@ -417,8 +628,8 @@ async function update() {
// 3. if people has and localPeople doesn't -> delete
if (peopleKeys.length !== 0 && validLocalPeople.length !== 0) {
peopleKeys.forEach(cp => {
const match = validLocalPeople.find(lp => cp.id === lp.id);
peopleKeys.forEach((cp) => {
const match = validLocalPeople.find((lp) => cp.id === lp.id);
if (!match) {
$deleteapi(apiName, cp.id);
}
@@ -427,17 +638,24 @@ async function update() {
// Ảnh
if (record.value.image && record.value.image.length > 0) {
await $insertapi("customerfile", record.value.image.map(v => ({ ref: customerId, file: v })), undefined, false);
await $insertapi(
"customerfile",
record.value.image.map((v) => ({ ref: customerId, file: v })),
undefined,
false,
);
}
const completeData = await $getdata("customer", { id: customerId }, undefined, true);
$snackbar(`Khách hàng đã được ${isNewCustomer.value ? "khởi tạo" : "cập nhật"} thành công`, "Thành công");
emit("modalevent", { name: "dataevent", data: completeData });
emit("update", completeData);
setTimeout(() => emit("close"), 100);
} catch (e) { console.error(e); }
} catch (e) {
console.error(e);
}
}
async function initData() {
@@ -465,7 +683,12 @@ async function initData() {
const copyData = $copy(props.application);
const type = props.customerType || copyData.type || 1;
selectCustomerType(type);
record.value = { ...record.value, ...copyData, id: undefined, code: undefined };
record.value = {
...record.value,
...copyData,
id: undefined,
code: undefined,
};
individualData.value = { ...individualData.value, ...copyData };
} else if (props.customerType) {
selectCustomerType(props.customerType);
@@ -473,4 +696,4 @@ async function initData() {
}
onMounted(() => initData());
</script>
</script>

View File

@@ -28,9 +28,7 @@
>
<div class="has-text-centered">
<div class="">
<SvgIcon
v-bind="{ name: 'building.svg', type: 'black', size: 40 }"
></SvgIcon>
<SvgIcon v-bind="{ name: 'building.svg', type: 'black', size: 40 }"></SvgIcon>
</div>
<div class="title is-6 mb-0">
{{ isVietnamese ? "Doanh nghiệp" : "Company" }}

View File

@@ -1,5 +1,8 @@
<template>
<div :id="docid" v-if="record">
<div
:id="docid"
v-if="record"
>
<div>
<Caption v-bind="{ title: this.data && findFieldName('info')[this.lang] }"></Caption>
<div class="columns is-multiline mx-0">
@@ -7,7 +10,11 @@
<div class="field">
<label class="label"> khách hàng</label>
<div class="control">
<span class="hyperlink" @click="$copyToClipboard(record.code)">{{ record.code }}</span>
<span
class="hyperlink"
@click="$copyToClipboard(record.code)"
>{{ record.code }}</span
>
</div>
</div>
</div>
@@ -23,14 +30,21 @@
<div class="field">
<label class="label">Điện thoại</label>
<div class="control">
<span class="hyperlink" @click="openPhone()">{{ record.phone }}</span>
<span
class="hyperlink"
@click="openPhone()"
>{{ record.phone }}</span
>
</div>
</div>
</div>
<div class="column is-3 pb-1 px-0">
<div class="field">
<label class="label">Email</label>
<div class="control" style="word-break: break-all">
<div
class="control"
style="word-break: break-all"
>
{{ record.email || "/" }}
</div>
</div>
@@ -103,7 +117,11 @@
<div class="field">
<label class="label">Người tạo</label>
<div class="control">
<span class="hyperlink" @click="openUser(record.creator)">{{ record.creator__fullname || "/" }}</span>
<span
class="hyperlink"
@click="openUser(record.creator)"
>{{ record.creator__fullname || "/" }}</span
>
</div>
</div>
</div>
@@ -122,7 +140,11 @@
<div class="field">
<label class="label">Người cập nhật</label>
<div class="control">
<span class="hyperlink" @click="openUser(record.updater)">{{ record.updater__fullname || "/" }}</span>
<span
class="hyperlink"
@click="openUser(record.updater)"
>{{ record.updater__fullname || "/" }}</span
>
</div>
</div>
</div>
@@ -131,7 +153,7 @@
<label class="label">Thời gian cập nhật</label>
<div class="control">
<span>
{{ record.update_time ? $dayjs(record.update_time).format("DD/MM/YYYY HH:mm") : '/' }}
{{ record.update_time ? $dayjs(record.update_time).format("DD/MM/YYYY HH:mm") : "/" }}
</span>
</div>
</div>
@@ -143,58 +165,137 @@
<ImageGallery v-bind="{ row: record, api: 'customerfile', hideopt: true }"></ImageGallery>
</div>
<div class="mt-3">
<Caption v-bind="{ title: this.isIndividual ? 'Người liên quan' : 'Người đại diện pháp luật' }"></Caption>
<Caption
v-bind="{
title: this.isIndividual ? 'Người liên quan' : 'Người đại diện pháp luật',
}"
></Caption>
<div class="mt-2">
<div
<div
v-if="this.relatedPeople && this.relatedPeople.length > 0"
v-for="relatedPerson in this.relatedPeople"
class="columns is-0 mb-2"
>
<span class="column is-2">{{ relatedPerson.people__code }}</span>
<span class="column is-4 ">
<span class="has-text-primary hyperlink"
<span class="column is-4">
<span
class="has-text-primary hyperlink"
@click="openRelatedPerson(relatedPerson.people)"
>{{ relatedPerson.people__fullname }}</span>
>{{ relatedPerson.people__fullname }}</span
>
<span> ({{ relatedPerson.relation__name }})</span>
</span>
<span class="column is-4">{{ relatedPerson.people__phone }}</span>
</div>
<div v-else class="has-text-grey">
Chưa {{ this.isIndividual ? 'người liên quan' : 'người đại diện pháp luật' }}
<div
v-else
class="has-text-grey"
>
Chưa có
{{ this.isIndividual ? "người liên quan" : "người đại diện pháp luật" }}
</div>
</div>
</div>
<div v-if="record.count_product >0" class="mt-3">
<Caption class="mb-2" v-bind="{ title: this.data && findFieldName('transaction')[this.lang] }"></Caption>
<DataView v-bind="{
setting: 'customer-all-transaction',
pagename: this.$id(),
api: 'customer',
params: {
filter: { id: this.row.customer || this.row.id },
/* copied from 02-connection.js */
values:
'id,update_time,creator,creator__fullname,country,country__name,country__en,issued_date,issued_place,issued_place__name,code,email,fullname,legal_code,phone,legal_type,legal_type__name,address,contact_address,note,type,type__name,updater,updater__fullname,create_time,update_time',
distinct_values: {
label: { type: 'Concat', field: ['code', 'fullname', 'phone', 'legal_code'] },
order: { type: 'RowNumber' },
image_count: { type: 'Count', field: 'id', subquery: { model: 'Customer_File', column: 'ref' } },
count_note: { type: 'Count', field: 'id', subquery: { model: 'Customer_Note', column: 'ref' } },
count_product: { type: 'Count', field: 'id', subquery: { model: 'Product_Booked', column: 'transaction__customer' } },
sum_product: { type: 'Sum', field: 'transaction__sale_price', subquery: { model: 'Product_Booked', column: 'transaction__customer' } },
sum_receiver: { type: 'Sum', field: 'transaction__amount_received', subquery: { model: 'Product_Booked', column: 'transaction__customer' } },
sum_remain: { type: 'Sum', field: 'transaction__amount_remain', subquery: { model: 'Product_Booked', column: 'transaction__customer' } }
<div
v-if="record.count_product > 0"
class="mt-3"
>
<Caption
class="mb-2"
v-bind="{ title: this.data && findFieldName('transaction')[this.lang] }"
></Caption>
<DataView
v-bind="{
setting: 'customer-all-transaction',
pagename: this.$id(),
api: 'customer',
params: {
filter: { id: this.row.customer || this.row.id },
/* copied from 02-connection.js */
values:
'id,update_time,creator,creator__fullname,country,country__name,country__en,issued_date,issued_place,issued_place__name,code,email,fullname,legal_code,phone,legal_type,legal_type__name,address,contact_address,note,type,type__name,updater,updater__fullname,create_time,update_time',
distinct_values: {
label: {
type: 'Concat',
field: ['code', 'fullname', 'phone', 'legal_code'],
},
order: { type: 'RowNumber' },
image_count: {
type: 'Count',
field: 'id',
subquery: { model: 'Customer_File', column: 'ref' },
},
count_note: {
type: 'Count',
field: 'id',
subquery: { model: 'Customer_Note', column: 'ref' },
},
count_product: {
type: 'Count',
field: 'id',
subquery: {
model: 'Product_Booked',
column: 'transaction__customer',
},
},
sum_product: {
type: 'Sum',
field: 'transaction__sale_price',
subquery: {
model: 'Product_Booked',
column: 'transaction__customer',
},
},
sum_receiver: {
type: 'Sum',
field: 'transaction__amount_received',
subquery: {
model: 'Product_Booked',
column: 'transaction__customer',
},
},
sum_remain: {
type: 'Sum',
field: 'transaction__amount_remain',
subquery: {
model: 'Product_Booked',
column: 'transaction__customer',
},
},
},
summary: 'annotate',
},
summary: 'annotate',
},
}" />
}"
/>
</div>
<div class="mt-4 border-bottom" id="ignore"></div>
<div class="buttons mt-2 is-flex is-gap-1" id="ignore">
<button v-if="$getEditRights('edit', { code: 'customer', category: 'topmenu' })" class="button is-primary" @click="edit()">Chỉnh sửa</button>
<button class="button is-light" @click="$exportpdf(docid, record.code)">In thông tin</button>
<div
class="mt-4 border-bottom"
id="ignore"
></div>
<div
class="buttons mt-2 is-flex is-gap-1"
id="ignore"
>
<button
v-if="$getEditRights('edit', { code: 'customer', category: 'topmenu' })"
class="button is-primary"
@click="edit()"
>
Chỉnh sửa
</button>
<button
class="button is-light"
@click="$exportpdf(docid, record.code)"
>
In thông tin
</button>
</div>
<Modal @close="showmodal = undefined" v-bind="showmodal" @dataevent="changeInfo" v-if="showmodal"></Modal>
<Modal
@close="showmodal = undefined"
v-bind="showmodal"
@dataevent="changeInfo"
v-if="showmodal"
></Modal>
</div>
</template>
<script>
@@ -225,15 +326,19 @@ export default {
},
isIndividual() {
return this.record.type === 1;
}
},
},
async created() {
this.record = await this.$getdata("customer", { id: this.row.customer || this.row.id }, undefined, true);
if (this.isIndividual) {
this.relatedPeople = await this.$getdata("customerpeople", { customer: this.row.customer || this.row.id });
this.relatedPeople = await this.$getdata("customerpeople", {
customer: this.row.customer || this.row.id,
});
} else {
const org = await this.$getdata('organization', { customer: this.row.customer || this.row.id }, undefined, true);
this.relatedPeople = await this.$getdata("legalrep", { organization: org.id });
const org = await this.$getdata("organization", { customer: this.row.customer || this.row.id }, undefined, true);
this.relatedPeople = await this.$getdata("legalrep", {
organization: org.id,
});
}
},
methods: {
@@ -270,10 +375,19 @@ export default {
this.record = this.$copy(v);
// refetch relatedPeople
if (this.isIndividual) {
this.relatedPeople = await this.$getdata("customerpeople", { customer: this.row.customer || this.row.id });
this.relatedPeople = await this.$getdata("customerpeople", {
customer: this.row.customer || this.row.id,
});
} else {
const org = await this.$getdata('organization', { customer: this.row.customer || this.row.id }, undefined, true);
this.relatedPeople = await this.$getdata("legalrep", { organization: org.id });
const org = await this.$getdata(
"organization",
{ customer: this.row.customer || this.row.id },
undefined,
true,
);
this.relatedPeople = await this.$getdata("legalrep", {
organization: org.id,
});
}
},
openUser(userId) {
@@ -287,15 +401,15 @@ export default {
};
},
async openRelatedPerson(peopleId) {
const peopleRow = await this.$getdata('people', { id: peopleId }, undefined, true);
const peopleRow = await this.$getdata("people", { id: peopleId }, undefined, true);
this.showmodal = {
component: "people/PeopleView",
vbind: { row: peopleRow },
title: 'Người liên quan',
width: '65%',
height: '400px',
}
}
title: "Người liên quan",
width: "65%",
height: "400px",
};
},
},
};
</script>