This commit is contained in:
Viet An
2026-07-06 11:25:42 +07:00
parent f72af58d78
commit be0be49454
22 changed files with 301 additions and 391 deletions

View File

@@ -1,17 +0,0 @@
<template>
<span class="tooltip">
<span v-html="props.html"></span>
<span
class="tooltiptext"
v-html="props.tooltip"
></span>
</span>
</template>
<script setup>
import { defineAsyncComponent } from "vue";
var props = defineProps({
html: String,
tooltip: String,
width: Number,
});
</script>

View File

@@ -267,20 +267,20 @@ const options = [
{ code: "system", name: "Của hệ thống" }, { code: "system", name: "Của hệ thống" },
{ code: "your", name: "Của bạn" }, { code: "your", name: "Của bạn" },
]; ];
var props = defineProps({ const props = defineProps({
pagename: String, pagename: String,
row: Object, row: Object,
}); });
var message = ref(); const message = ref();
var image = ref(); const image = ref();
var file = ref(); const file = ref();
var link = ref(); const link = ref();
var tab = ref("message"); const tab = ref("message");
var record = await $getdata("useraction", { let record = await $getdata("useraction", {
first: true, first: true,
filter: { user: 1, action: props.row.id }, filter: { user: 1, action: props.row.id },
}); });
var option = ref(record ? "your" : "system"); const option = ref(record ? "your" : "system");
function getValue() { function getValue() {
if (option.value === "your") { if (option.value === "your") {
message.value = record ? $copy(record.message || [{ code: $id() }]) : [{ code: $id() }]; message.value = record ? $copy(record.message || [{ code: $id() }]) : [{ code: $id() }];

View File

@@ -1,63 +1,36 @@
<template> <script lang="ts" setup>
<ClientOnly>
<QuillEditor
v-model:content="content"
content-type="html"
theme="snow"
:toolbar="toolbarOptions"
@text-change="textChange"
:style="`font-size: 16px; height: ${props.height};`"
/>
</ClientOnly>
</template>
<script setup>
import { QuillEditor } from "@vueup/vue-quill"; import { QuillEditor } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css"; import "@vueup/vue-quill/dist/vue-quill.snow.css";
const emit = defineEmits(["content", "modalevent"]); const props = defineProps({ text: String });
const emit = defineEmits(["content"]);
const props = defineProps({
text: String,
row: Object,
pagename: String,
api: String,
height: {
type: String,
default: "450px",
},
});
// Custom toolbar options
const toolbarOptions = [ const toolbarOptions = [
// 🔤 Font chữ
[{ font: [] }], [{ font: [] }],
// 🔠 Cỡ chữ
[{ header: [1, 2, 3, 4, 5, 6, false] }], [{ header: [1, 2, 3, 4, 5, 6, false] }],
["bold", "italic", "underline", "strike"], // Định dạng cơ bản
// ✍️ Định dạng cơ bản ["blockquote", "code-block"],
["bold", "italic", "underline", "strike"], [{ color: [] }, { background: [] }], // Màu chữ & nền
[{ align: [] }], // Căn lề
// 🎨 Màu chữ & nền
[{ color: [] }, { background: [] }],
// 📐 Căn lề
[{ align: [] }],
// 📋 Danh sách
[{ list: "ordered" }, { list: "bullet" }], [{ list: "ordered" }, { list: "bullet" }],
["link", "image", "video"], // Media
// 🔗 Media
["link", "image", "video"],
["clean"], // Xóa định dạng ["clean"], // Xóa định dạng
]; ];
var content = props.text; const content = ref(props.text);
function textChange() { function textChange() {
emit("content", content); console.log("content", content.value);
emit("modalevent", { name: "content", data: content }); emit("content", content.value);
} }
</script> </script>
<template>
<QuillEditor
v-model:content="content"
:toolbar="toolbarOptions"
@textChange="textChange"
content-type="html"
theme="snow"
style="height: 400px"
/>
</template>

View File

@@ -199,34 +199,36 @@
import InputPhone from "~/components/common/InputPhone"; import InputPhone from "~/components/common/InputPhone";
import InputEmail from "~/components/common/InputEmail"; import InputEmail from "~/components/common/InputEmail";
import SearchBox from "~/components/SearchBox"; import SearchBox from "~/components/SearchBox";
var props = defineProps({
const props = defineProps({
pagename: String, pagename: String,
row: Object, row: Object,
}); });
const store = useStore(); const store = useStore();
const { $find, $getdata, $patchapi, $insertapi, $findapi, $getapi, $empty, $errPhone, $resetNull, $snackbar } = const { $find, $getdata, $patchapi, $insertapi, $findapi, $getapi, $empty, $errPhone, $resetNull, $snackbar } =
useNuxtApp(); useNuxtApp();
const emit = defineEmits(["update", "dataevent"]); const emit = defineEmits(["update", "dataevent"]);
var viewport = store.viewport; const viewport = store.viewport;
var errors = ref({}); const errors = ref({});
var record = ref(); const record = ref();
var showmodal = undefined; const showmodal = ref();
var existedCustomer = undefined; let existedCustomer = undefined;
async function initData() { async function initData() {
if (props.row) { if (props.row) {
let conn = $findapi("company"); const conn = $findapi("company");
conn.params.filter = { conn.params.filter = {
id: props.row.company || props.row.customer__company || props.row.id, id: props.row.company || props.row.customer__company || props.row.id,
}; };
let rs = await $getapi([conn]); const rs = await $getapi([conn]);
let found = $find(rs, { name: "company" }); const found = $find(rs, { name: "company" });
if (found.data.rows.length > 0) record.value = found.data.rows[0]; if (found.data.rows.length > 0) record.value = found.data.rows[0];
} else { } else {
record.value = {}; record.value = {};
} }
} }
function findLang(code) { function findLang(code) {
let found = $find(store.common, { code: code }); const found = $find(store.common, { code: code });
return found ? found[store.lang] : ""; return found ? found[store.lang] : "";
} }
function showCustomer() { function showCustomer() {
@@ -269,13 +271,13 @@ async function update() {
if (!record.value.creator) record.value.creator = store.login.id; if (!record.value.creator) record.value.creator = store.login.id;
record.value.updater = store.login.id; record.value.updater = store.login.id;
record.update_time = new Date(); record.update_time = new Date();
let rs = record.value.id const rs = record.value.id
? await $patchapi("company", { data: record.value }) ? await $patchapi("company", { data: record.value })
: await $insertapi("company", { data: record.value }); : await $insertapi("company", { data: record.value });
if (rs === "error") return; 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>`, "Success"); if (!record.value.id) $snackbar(`Khách hàng đã được khởi tạo với mã <b>${rs.code}</b>`, "Success");
record.value.id = rs.id; record.value.id = rs.id;
let ele = await $getdata("company", { const ele = await $getdata("company", {
first: true, first: true,
filter: { id: rs.id }, filter: { id: rs.id },
}); });

View File

@@ -2,38 +2,21 @@
<!-- Nội dung chính - chỉ hiển thị form nhân (màn hình chọn đã được xử SearchBox) --> <!-- Nội dung chính - chỉ hiển thị form nhân (màn hình chọn đã được xử SearchBox) -->
<div class="columns mx-0 px-0 py-2"> <div class="columns mx-0 px-0 py-2">
<div <div
:class="`column is-narrow p-0 pr-4 ${viewport === 1 ? 'px-0' : ''}`" :class="['column is-narrow p-0 pr-4', store.viewport === 1 && 'px-0']"
:style="`${viewport === 1 ? '' : 'border-right: 1px solid #B0B0B0;'}`" :style="{ borderRight: store.viewport > 1 ? '1px solid var(--bulma-border)' : 'initial' }"
> >
<template v-if="viewport > 1"> <div :class="['buttons is-align-items-stretch', store.viewport > 1 && 'is-flex-direction-column']">
<div <button
v-for="(v, i) in tabs" v-for="(v, i) in tabs"
:key="i" :key="i"
:class="['is-clickable p-3', i !== 0 && 'mt-2', getStyle(v)]" :class="['button is-justify-content-flex-start', v.code === tab ? 'is-primary' : 'is-light']"
style="width: 130px; border-radius: 4px"
@click="changeTab(v)" @click="changeTab(v)"
> >
{{ isVietnamese ? v.name : v.en }} {{ isVietnamese ? v.name : v.en }}
</div> </button>
</template>
<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 }}
</div> </div>
</div> </div>
</div> <div :class="['column', { 'px-0': store.viewport === 1 }]">
</div>
</div>
<div :class="['column', { 'px-0': viewport === 1 }]">
<CustomerForm <CustomerForm
v-if="tab === 'info' && record !== undefined" v-if="tab === 'info' && record !== undefined"
v-bind="{ row: record, pagename, application }" v-bind="{ row: record, pagename, application }"
@@ -50,22 +33,21 @@
}" }"
@update="update" @update="update"
v-if="tab === 'image'" v-if="tab === 'image'"
></ImageGallery> />
<CustomerView <CustomerView
v-bind="{ row: record, pagename: pagename }" v-bind="{ row: record, pagename: pagename }"
@update="update" @update="update"
@close="emit('close')" @close="emit('close')"
v-if="tab === 'print'" v-if="tab === 'print'"
></CustomerView> />
</template> </template>
</div> </div>
</div> </div>
<Modal <Modal
@close="handleModalClose"
v-bind="showmodal"
v-if="showmodal" v-if="showmodal"
></Modal> v-bind="showmodal"
@close="showmodal.value = undefined"
/>
</template> </template>
<script setup> <script setup>
import CustomerForm from "~/components/customer/CustomerForm.vue"; import CustomerForm from "~/components/customer/CustomerForm.vue";
@@ -85,24 +67,14 @@ const props = defineProps({
const isVietnamese = computed(() => store.lang === "vi"); const isVietnamese = computed(() => store.lang === "vi");
const emit = defineEmits(["modalevent", "close"]); const emit = defineEmits(["modalevent", "close"]);
var viewport = 5; const tabs = [
var tabs = [
{ code: "info", name: "1. Thông tin", en: "1. Information", active: true }, { code: "info", name: "1. Thông tin", en: "1. Information", active: true },
{ code: "image", name: "2. Hình ảnh", en: "2. Images", active: false }, { code: "image", name: "2. Hình ảnh", en: "2. Images", active: false },
{ code: "print", name: "3. Bản in", en: "3. Print", active: false }, { code: "print", name: "3. Bản in", en: "3. Print", active: false },
]; ];
var tab = ref("info"); const tab = ref("info");
var record = props.row || null; let record = props.row || null;
var showmodal = ref(); const showmodal = ref();
function getStyle(v) {
let check = record ? record.id : false;
// let check = props.isEditMode;
if (v.tab === "info") check = true;
return v.code === tab.value
? "has-background-primary has-text-white"
: `has-background-light ${check ? "" : "has-text-grey"}`;
}
function changeTab(v) { function changeTab(v) {
if (tab.value === v.code) return; if (tab.value === v.code) return;
@@ -110,10 +82,6 @@ function changeTab(v) {
tab.value = v.code; tab.value = v.code;
} }
function handleModalClose() {
showmodal.value = undefined;
}
function update(v) { function update(v) {
record = { record = {
...v, ...v,
@@ -123,16 +91,3 @@ function update(v) {
if (!props.isEditMode) emit("close"); if (!props.isEditMode) emit("close");
} }
</script> </script>
<style scoped>
.title {
font-family: "Segoe UI", "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif !important;
}
.button.is-large.is-fullwidth:hover {
color: white !important;
background-color: rgb(75, 114, 243) !important;
.title {
color: white !important;
}
}
</style>

View File

@@ -446,10 +446,10 @@ const store = useStore();
const { colorchoice } = store; const { colorchoice } = store;
const errors = ref([]); const errors = ref([]);
const currentTab = ref("value"); const currentTab = ref("value");
var pagedata = store[props.pagename]; let pagedata = store[props.pagename];
var fields = []; let fields = [];
var currentField = $copy(props.field); let currentField = $copy(props.field);
var { label } = currentField; let { label } = currentField;
const showmodal = ref(); const showmodal = ref();
const checkFilter = function () {}; const checkFilter = function () {};
const getMenu = function () { const getMenu = function () {
@@ -461,33 +461,33 @@ const getMenu = function () {
return array; return array;
}; };
var selectTab = getMenu()[0]; var selectTab = getMenu()[0];
var datatype = store.datatype; let datatype = store.datatype;
// var current = 1; // let current = 1;
// var value1 = undefined; // let value1 = undefined;
// var value2 = undefined; // let value2 = undefined;
const moneyunit = store.moneyunit; const moneyunit = store.moneyunit;
const radioType = store.datatype.find((v) => v.code === currentField.format); const radioType = store.datatype.find((v) => v.code === currentField.format);
// var selectUnit = currentField.format === "number" ? moneyunit.find((v) => v.detail === currentField.unit) : undefined; // let selectUnit = currentField.format === "number" ? moneyunit.find((v) => v.detail === currentField.unit) : undefined;
// var bgcolor = undefined; // let bgcolor = undefined;
// var radioBGcolor = colorchoice.find((v) => v.code === "none"); // let radioBGcolor = colorchoice.find((v) => v.code === "none");
// var color = undefined; // let color = undefined;
// var radioColor = colorchoice.find((v) => v.code === "none"); // let radioColor = colorchoice.find((v) => v.code === "none");
// var textsize = undefined; // let textsize = undefined;
// var radioSize = colorchoice.find((v) => v.code === "none"); // let radioSize = colorchoice.find((v) => v.code === "none");
var minwidth = undefined; let minwidth = undefined;
var radioWidth = colorchoice.find((v) => v.code === "none"); let radioWidth = colorchoice.find((v) => v.code === "none");
var radioMaxWidth = colorchoice.find((v) => v.code === "none"); let radioMaxWidth = colorchoice.find((v) => v.code === "none");
var maxwidth = undefined; let maxwidth = undefined;
// var selectAlign = undefined; // let selectAlign = undefined;
// var radioAlign = colorchoice.find((v) => v.code === "none"); // let radioAlign = colorchoice.find((v) => v.code === "none");
var radioTemplate = ref(colorchoice.find((v) => v.code === (currentField.template ? "option" : "none"))["code"]); let radioTemplate = ref(colorchoice.find((v) => v.code === (currentField.template ? "option" : "none"))["code"]);
// var selectPlacement = store.placement.find((v) => v.code === "is-right"); // let selectPlacement = store.placement.find((v) => v.code === "is-right");
// var selectScheme = store.colorscheme.find((v) => v.code === "is-primary"); // let selectScheme = store.colorscheme.find((v) => v.code === "is-primary");
// var radioTooltip = store.colorchoice.find((v) => v.code === "none"); // let radioTooltip = store.colorchoice.find((v) => v.code === "none");
// var selectField = undefined; // let selectField = undefined;
// var tags = currentField.tags ? currentField.tags.map((v) => fields.find((x) => x.name === v)) : []; // let tags = currentField.tags ? currentField.tags.map((v) => fields.find((x) => x.name === v)) : [];
// var formula = currentField.formula ? currentField.formula : undefined; // let formula = currentField.formula ? currentField.formula : undefined;
var decimal = currentField.decimal; let decimal = currentField.decimal;
let shortmenu = store.menuchoice.filter((x) => let shortmenu = store.menuchoice.filter((x) =>
currentField.format === "number" currentField.format === "number"
? currentField.formula ? currentField.formula
@@ -498,7 +498,7 @@ let shortmenu = store.menuchoice.filter((x) =>
var selectTab = shortmenu.find((v) => selectTab.code === v.code) var selectTab = shortmenu.find((v) => selectTab.code === v.code)
? selectTab ? selectTab
: menuchoice.find((v) => v.code === "value"); : menuchoice.find((v) => v.code === "value");
var search = undefined; let search = undefined;
// if(selectTab.code==='value') { // if(selectTab.code==='value') {
// let self = this // let self = this
// setTimeout(function() {self.$refs[currentField.name]? self.$refs[currentField.name].focus() : false}, 50) // setTimeout(function() {self.$refs[currentField.name]? self.$refs[currentField.name].focus() : false}, 50)

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-if="docid"> <div v-if="$id()">
<div class="field is-horizontal"> <div class="field is-horizontal">
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
@@ -74,17 +74,21 @@
v-if="type.code !== 'tag'" v-if="type.code !== 'tag'"
> >
<label class="label">Outline</label> <label class="label">Outline</label>
<p class="control fs-14"> <div class="control fs-14 is-flex is-gap-2">
<b-radio <label
v-for="(v, i) in outlines" v-for="(v, i) in outlines"
:key="i" :key="i"
v-model="outline" class="radio"
:native-value="v"
@input="changeType(v)"
> >
<input
v-model="outline"
@change="changeType(v)"
type="radio"
name="outline"
/>
{{ v.name }} {{ v.name }}
</b-radio> </label>
</p> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -367,6 +371,7 @@
</div> </div>
</template> </template>
<template v-else-if="tab.code === 'template'"> <template v-else-if="tab.code === 'template'">
<div class="block">
<div class="buttons has-addons mb-3"> <div class="buttons has-addons mb-3">
<button <button
@click="copyContent()" @click="copyContent()"
@@ -399,7 +404,8 @@
v-model="text" v-model="text"
@dblclick="doCheck" @dblclick="doCheck"
></textarea> ></textarea>
<p class="mt-5"> </div>
<div class="block">
<span class="icon-text"> <span class="icon-text">
<span class="fs-17 font-semibold">Replace</span> <span class="fs-17 font-semibold">Replace</span>
<span class="icon"> <span class="icon">
@@ -409,8 +415,8 @@
/> />
</span> </span>
</span> </span>
</p> </div>
<div class="field is-grouped mt-4"> <div class="field is-grouped">
<div class="control"> <div class="control">
<label class="label">Đoạn text</label> <label class="label">Đoạn text</label>
<input <input
@@ -441,14 +447,12 @@
</button> </button>
</div> </div>
</div> </div>
<p class="mt-5">
<button <button
class="button is-primary has-text-white" class="button is-primary has-text-white"
@click="changeTemplate()" @click="changeTemplate()"
> >
Áp dụng Áp dụng
</button> </button>
</p>
</template> </template>
</div> </div>
</template> </template>
@@ -456,61 +460,61 @@
import { ref } from "vue"; import { ref } from "vue";
const store = useStore(); const store = useStore();
const { $id, $copy, $empty, $calc, $remove, $copyToClipboard } = useNuxtApp(); const { $id, $copy, $empty, $calc, $remove, $copyToClipboard } = useNuxtApp();
var props = defineProps({ const props = defineProps({
pagename: String, pagename: String,
field: Object, field: Object,
}); });
var colorscheme = store.colorscheme; let colorscheme = store.colorscheme;
var colorchoice = store.colorchoice; let colorchoice = store.colorchoice;
var pageData = store[props.pagename]; let pageData = store[props.pagename];
var field = props.field; let field = props.field;
var type = undefined; let type = undefined;
var size = undefined; let size = undefined;
var types = [ const types = [
{ code: "span", name: "span" }, { code: "span", name: "span" },
{ code: "tag", name: "tag" }, { code: "tag", name: "tag" },
]; ];
var sizes = [ const sizes = [
{ code: "is-small", name: "Nhỏ", value: "is-size-6" }, { code: "is-small", name: "Nhỏ", value: "is-size-6" },
{ code: "is-normal", name: "Trung bình", value: "is-size-5" }, { code: "is-normal", name: "Trung bình", value: "is-size-5" },
{ code: "is-medium", name: "Lớn", value: "is-size-4" }, { code: "is-medium", name: "Lớn", value: "is-size-4" },
]; ];
var shapes = [ const shapes = [
{ code: "default", name: "Mặc định" }, { code: "default", name: "Mặc định" },
{ code: "is-rounded", name: "Tròn góc" }, { code: "is-rounded", name: "Tròn góc" },
]; ];
var shape = undefined; let shape = undefined;
var outlines = [ const outlines = [
{ code: "default", name: "Mặc định" }, { code: "default", name: "Mặc định" },
{ code: "is-outlined", name: "Outline" }, { code: "is-outlined", name: "Outline" },
]; ];
var outline = undefined; let outline = undefined;
var conditions = [ const conditions = [
{ code: "no", name: "Không áp dụng" }, { code: "no", name: "Không áp dụng" },
{ code: "yes", name: "Có áp dụng" }, { code: "yes", name: "Có áp dụng" },
]; ];
var condition = undefined; let condition = undefined;
const tags = ref([]); const tags = ref([]);
var selected = undefined; let selected = undefined;
var tabs = [ const tabs = [
{ code: "selected", name: "Bước 1: Tạo nội dung" }, { code: "selected", name: "Bước 1: Tạo nội dung" },
{ code: "condition", name: "Bước 2: Đặt điều kiện" }, { code: "condition", name: "Bước 2: Đặt điều kiện" },
{ code: "option", name: "Bước 3: Chọn màu, cỡ chữ" }, { code: "option", name: "Bước 3: Chọn màu, cỡ chữ" },
{ code: "template", name: "Bước 4: Mã lệnh & áp dụng" }, { code: "template", name: "Bước 4: Mã lệnh & áp dụng" },
]; ];
var tab = ref(undefined); const tab = ref(undefined);
var tagsField = []; let tagsField = [];
var errors = []; let errors = [];
var expression = ""; let expression = "";
var text = ref(null); const text = ref(null);
var radioBGcolor = undefined; let radioBGcolor = undefined;
var radioColor = undefined; let radioColor = undefined;
var radioSize = undefined; let radioSize = undefined;
var bgcolor = undefined; let bgcolor = undefined;
var color = undefined; let color = undefined;
var textsize = undefined; let textsize = undefined;
var source = undefined; let source = undefined;
var target = $copy(field.name); let target = $copy(field.name);
const initData = function () { const initData = function () {
type = types.find((v) => v.code === "tag"); type = types.find((v) => v.code === "tag");
@@ -653,5 +657,4 @@ const getSpanClass = function (v) {
return value; return value;
}; };
initData(); initData();
var docid = $id();
</script> </script>

View File

@@ -167,26 +167,26 @@ function dynamicComponent(htmlString) {
}, },
}); });
} }
var timer = undefined; let timer = undefined;
var showPaging = ref(false); const showPaging = ref(false);
var totalRows = ref(0); const totalRows = ref(0);
var currentPage = 1; let currentPage = 1;
var displayFields = ref([]); const displayFields = ref([]);
var displayData = []; let displayData = [];
var pagedata = store[props.pagename]; let pagedata = store[props.pagename];
let tablesetting = $copy(isEmpty(pagedata.tablesetting) ? store.tablesetting : pagedata.tablesetting); let tablesetting = $copy(isEmpty(pagedata.tablesetting) ? store.tablesetting : pagedata.tablesetting);
if (!Array.isArray(tablesetting)) { if (!Array.isArray(tablesetting)) {
tablesetting = Object.values(tablesetting); tablesetting = Object.values(tablesetting);
} }
var perPage = Number($find(tablesetting, { code: "per-page" }, "detail")) || 20; let perPage = Number($find(tablesetting, { code: "per-page" }, "detail")) || 20;
var filters = $copy(pagedata.filters || []); let filters = $copy(pagedata.filters || []);
var currentField; let currentField;
var filterData = []; let filterData = [];
var currentsetting; let currentsetting;
var scrollbar; let scrollbar;
var fields; let fields;
var currentRow; let currentRow;
var data = $copy(pagedata.data); let data = $copy(pagedata.data);
const showmodal = ref(); const showmodal = ref();
watch( watch(
() => store[props.pagename], () => store[props.pagename],
@@ -428,7 +428,7 @@ const frontendFilter = function (newVal) {
} }
}; };
newVal = $copy(newVal); newVal = $copy(newVal);
var data = $copy(pagedata.data); let data = $copy(pagedata.data);
newVal newVal
.filter((m) => m.select || m.filter) .filter((m) => m.select || m.filter)
.map((v) => { .map((v) => {
@@ -487,14 +487,14 @@ const doSelect = function (value) {
updateShow(); updateShow();
}; };
const doubleScroll = function (element) { const doubleScroll = function (element) {
var _scrollbar = document.createElement("div"); const _scrollbar = document.createElement("div");
_scrollbar.appendChild(document.createElement("div")); _scrollbar.appendChild(document.createElement("div"));
_scrollbar.style.overflow = "auto"; _scrollbar.style.overflow = "auto";
_scrollbar.style.overflowY = "hidden"; _scrollbar.style.overflowY = "hidden";
_scrollbar.firstChild.style.width = element.scrollWidth + "px"; _scrollbar.firstChild.style.width = element.scrollWidth + "px";
_scrollbar.firstChild.style.height = "1px"; _scrollbar.firstChild.style.height = "1px";
_scrollbar.firstChild.appendChild(document.createTextNode("\xA0")); _scrollbar.firstChild.appendChild(document.createTextNode("\xA0"));
var running = false; let running = false;
_scrollbar.onscroll = function () { _scrollbar.onscroll = function () {
if (running) { if (running) {
running = false; running = false;

View File

@@ -204,7 +204,7 @@ export default {
changeStyle() { changeStyle() {
let check = this.field.format === "number" ? this.checkExpression() : this.checkCondition(); let check = this.field.format === "number" ? this.checkExpression() : this.checkCondition();
if (!check) return; if (!check) return;
var row = const row =
this.field.format === "number" this.field.format === "number"
? { ? {
expression: this.expression, expression: this.expression,

View File

@@ -36,7 +36,7 @@
/> />
<p <p
class="fs-14 mt-1" class="fs-14 mt-1"
:class="currentField.format === 'string' ? 'mb-1' : 'mb-2'" :class="props.currentField.format === 'string' ? 'mb-1' : 'mb-2'"
> >
<a <a
class="has-text-primary mr-5" class="has-text-primary mr-5"
@@ -74,7 +74,7 @@
/> />
<p <p
class="fs-14 mt-1" class="fs-14 mt-1"
:class="currentField.format === 'string' ? 'mb-1' : 'mb-2'" :class="props.currentField.format === 'string' ? 'mb-1' : 'mb-2'"
> >
<a <a
class="has-text-primary mr-5" class="has-text-primary mr-5"
@@ -112,7 +112,7 @@
/> />
<p <p
class="fs-14 mt-1" class="fs-14 mt-1"
:class="currentField.format === 'string' ? 'mb-1' : 'mb-2'" :class="props.currentField.format === 'string' ? 'mb-1' : 'mb-2'"
> >
<a <a
class="has-text-primary mr-5" class="has-text-primary mr-5"
@@ -148,7 +148,7 @@
<span>Copy</span> <span>Copy</span>
</button> </button>
<button <button
@click="paste()" @click="paste"
class="button is-primary is-light fs-14" class="button is-primary is-light fs-14"
> >
<span class="icon"> <span class="icon">
@@ -164,7 +164,7 @@
class="textarea fs-13 is-family-monospace" class="textarea fs-13 is-family-monospace"
rows="4" rows="4"
v-model="script" v-model="script"
@change="checkScript()" @change="checkScript"
@dblclick="doCheck" @dblclick="doCheck"
></textarea> ></textarea>
<p class="mt-5"> <p class="mt-5">
@@ -193,19 +193,14 @@
<input <input
class="input" class="input"
type="text" type="text"
placeholder=""
v-model="target" v-model="target"
/> />
</div> </div>
<div class="control"> <div class="control">
<label <label class="label is-sr-only">Hidden</label>
class="label"
style="opacity: 0"
>Hidden</label
>
<button <button
class="button is-primary is-light" class="button is-primary is-light"
@click="replace()" @click="replace"
> >
Replace Replace
</button> </button>
@@ -225,22 +220,20 @@
<p class="mt-4"> <p class="mt-4">
<button <button
class="button is-primary is-rounded" class="button is-primary is-rounded"
@click="changeScript()" @click="changeScript"
> >
Cập nhật Cập nhật
</button> </button>
</p> </p>
</template> </template>
<TableOption <TableOption
v-bind="{ pagename }"
v-else-if="sideBar === 'option'" v-else-if="sideBar === 'option'"
> v-bind="{ pagename }"
</TableOption> />
<CreateTemplate <CreateTemplate
v-else-if="sideBar === 'template'" v-else-if="sideBar === 'template'"
v-bind="{ pagename, field: openField }" v-bind="{ pagename, field: openField }"
> />
</CreateTemplate>
</template> </template>
<script setup> <script setup>
import CreateTemplate from "~/components/datatable/CreateTemplate"; import CreateTemplate from "~/components/datatable/CreateTemplate";
@@ -252,21 +245,20 @@ const props = defineProps({
currentField: Object, currentField: Object,
pagename: String, pagename: String,
}); });
var currentField = props.currentField; let openField = {};
var openField = {}; let bgcolorFilter = [];
var bgcolorFilter = []; let colorFilter = [];
var colorFilter = []; let sizeFilter = [];
var sizeFilter = []; const sideBar = ref();
var sideBar = ref(); let script = undefined;
var script = undefined; let radio = undefined;
var radio = undefined; const tabs = [
var tabs = [
{ code: "expression", name: "Biểu thức" }, { code: "expression", name: "Biểu thức" },
{ code: "script", name: "Mã lệnh" }, { code: "script", name: "Mã lệnh" },
]; ];
const tab = ref({ code: "expression", name: "Biểu thức" }); const tab = ref({ code: "expression", name: "Biểu thức" });
var source = undefined; let source = undefined;
var target = $copy(currentField.name); let target = $copy(props.currentField.name);
const initData = function () { const initData = function () {
openField = props.event.field; openField = props.event.field;
@@ -326,7 +318,7 @@ const changeScript = function () {
}; };
const doConditionFilter = function (v, type, id) { const doConditionFilter = function (v, type, id) {
v.id = id; v.id = id;
let copy = $copy(currentField); let copy = $copy(props.currentField);
if (copy[type] ? Array.isArray(copy[type]) : false) { if (copy[type] ? Array.isArray(copy[type]) : false) {
let idx = copy[type].findIndex((x) => x.id === id); let idx = copy[type].findIndex((x) => x.id === id);
idx >= 0 ? (copy[type][idx] = v) : copy[type].push(v); idx >= 0 ? (copy[type][idx] = v) : copy[type].push(v);

View File

@@ -261,7 +261,7 @@ import { cloneDeep } from "es-toolkit";
const emit = defineEmits(["modalevent"]); const emit = defineEmits(["modalevent"]);
const store = useStore(); const store = useStore();
const { $id, $copy, $empty, $stripHtml, $createField, $calc, $isNumber } = useNuxtApp(); const { $id, $copy, $empty, $stripHtml, $createField, $calc, $isNumber } = useNuxtApp();
var props = defineProps({ const props = defineProps({
pagename: String, pagename: String,
field: Object, field: Object,
filters: Object, filters: Object,
@@ -270,29 +270,29 @@ var props = defineProps({
}); });
const moneyunit = store.moneyunit || []; const moneyunit = store.moneyunit || [];
const datatype = store.datatype; const datatype = store.datatype;
var showmodal = ref(); const showmodal = ref();
var pagedata = store[props.pagename]; let pagedata = store[props.pagename];
var selectUnit = moneyunit.find((v) => v.code === "one"); let selectUnit = moneyunit.find((v) => v.code === "one");
var data = []; let data = [];
var current = 1; let current = 1;
var filterData = []; let filterData = [];
var loading = false; let loading = false;
const fieldTypes = [ const fieldTypes = [
{ code: "empty", name: "Tạo cột rỗng" }, { code: "empty", name: "Tạo cột rỗng" },
{ code: "formula", name: "Tạo công thức" }, { code: "formula", name: "Tạo công thức" },
]; ];
var tags = []; let tags = [];
var formula = undefined; let formula = undefined;
var name = `f${$id().toLocaleLowerCase()}`; let name = `f${$id().toLocaleLowerCase()}`;
var label = undefined; let label = undefined;
const errors = ref([]); const errors = ref([]);
var selectType = fieldTypes.find((v) => v.code === "empty"); const selectType = ref(fieldTypes.find((v) => v.code === "empty"));
var radioType = ref(datatype.find((v) => v.code === "string")); const radioType = ref(datatype.find((v) => v.code === "string"));
var fields = []; let fields = [];
var options = undefined; let options = undefined;
var columns = $copy(pagedata.fields.filter((v) => v.format === "number")); let columns = $copy(pagedata.fields.filter((v) => v.format === "number"));
var decimal = undefined; let decimal = undefined;
var choices = [ const choices = [
{ code: "column", name: "Dùng cột dữ liệu" }, { code: "column", name: "Dùng cột dữ liệu" },
{ code: "function", name: "Dùng hàm số" }, { code: "function", name: "Dùng hàm số" },
]; ];
@@ -303,10 +303,10 @@ const funcs = [
{ code: "min", name: "Min" }, { code: "min", name: "Min" },
{ code: "avg", name: "Avg" }, { code: "avg", name: "Avg" },
]; ];
var func = "sum"; let func = "sum";
var placeholder = "Minh hoạ công thức: f10001 + f10002"; let placeholder = "Minh hoạ công thức: f10001 + f10002";
var args = undefined; let args = undefined;
var operator = [ let operator = [
{ code: "+", name: "Cộng" }, { code: "+", name: "Cộng" },
{ code: "-", name: "Trừ" }, { code: "-", name: "Trừ" },
{ code: "*", name: "Nhân" }, { code: "*", name: "Nhân" },

View File

@@ -184,7 +184,7 @@ if (!Array.isArray(pagedata.tablesetting)) {
const getDetail = (code) => tablesetting.find((v) => v.code === code)?.detail || ""; const getDetail = (code) => tablesetting.find((v) => v.code === code)?.detail || "";
const errors = ref([]); const errors = ref([]);
let radioNote = "no"; let radioNote = "no";
var tablesetting = pagedata.tablesetting; let tablesetting = pagedata.tablesetting;
let found = getDetail("note"); let found = getDetail("note");
if (found !== "@") radioNote = "yes"; if (found !== "@") radioNote = "yes";

View File

@@ -80,7 +80,8 @@
class="column p-0.5 fs-14" class="column p-0.5 fs-14"
> >
<a v-if="m.event && m.currentMonth === m.mothCondition"> <a v-if="m.event && m.currentMonth === m.mothCondition">
<Tooltip v-bind="{ html: m.event.html, tooltip: m.event.tooltip }"></Tooltip> <span>{{ m.event.html }}</span>
<span class="tooltiptext">{{ m.event.tooltip }}</span>
</a> </a>
<span <span
class="has-background-primary-soft p-1" class="has-background-primary-soft p-1"

View File

@@ -1,6 +1,12 @@
<script setup> <script setup>
import ActionInfo from "~/components/common/ActionInfo.vue";
import Editor from "~/components/common/Editor.vue";
import Company from "~/components/customer/Company.vue";
import Customer from "~/components/customer/Customer.vue";
import DataView from "~/components/datatable/DataView.vue"; import DataView from "~/components/datatable/DataView.vue";
import InventoryHighlightCard from "~/components/inventory/InventoryHighlightCard.vue"; import InventoryHighlightCard from "~/components/inventory/InventoryHighlightCard.vue";
import Common from "~/components/parameter/Common.vue";
import PeopleInfo from "~/components/people/PeopleInfo.vue";
const inventoryHighlights = [ const inventoryHighlights = [
{ {

View File

@@ -34,7 +34,7 @@
</div> </div>
</template> </template>
<script setup> <script setup>
var array = [ const array = [
{ {
code: "transactionphase", code: "transactionphase",
name: "Giai đoạn giao dịch", name: "Giai đoạn giao dịch",
@@ -167,7 +167,7 @@ var array = [
}, },
}, },
]; ];
var current = ref(array[0]); const current = ref(array[0]);
function changeTab(v) { function changeTab(v) {
current.value = null; current.value = null;
setTimeout(() => (current.value = v)); setTimeout(() => (current.value = v));

View File

@@ -248,11 +248,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick } from "vue";
import { render } from "@vue-email/render"; import { render } from "@vue-email/render";
import Modal from "~/components/Modal.vue"; import Modal from "~/components/Modal.vue";
import Template1 from "~/components/marketing/email/Template1.vue"; import Template1 from "~/components/marketing/email/Template1.vue";
import SvgIcon from "~/components/SvgIcon.vue";
import Editor from "~/components/common/Editor.vue"; import Editor from "~/components/common/Editor.vue";
const nuxtApp = useNuxtApp(); const nuxtApp = useNuxtApp();

View File

@@ -72,7 +72,7 @@ export default {
this.openCamera(); this.openCamera();
}, },
beforeDestroy() { beforeDestroy() {
var vidTrack = this.video.srcObject.getVideoTracks(); const vidTrack = this.video.srcObject.getVideoTracks();
vidTrack.forEach((track) => { vidTrack.forEach((track) => {
track.stop(); track.stop();
track.enabled = false; track.enabled = false;

View File

@@ -51,14 +51,14 @@
<script setup> <script setup>
import { onMounted } from "vue"; import { onMounted } from "vue";
const { $copy, $resetNull, $insertrow, $updaterow, $snackbar } = useNuxtApp(); const { $copy, $resetNull, $insertrow, $updaterow, $snackbar } = useNuxtApp();
var props = defineProps({ const props = defineProps({
api: String, api: String,
pagename: String, pagename: String,
row: Object, row: Object,
prefix: String, prefix: String,
}); });
const emit = defineEmits(["close", "modalevent"]); const emit = defineEmits(["close", "modalevent"]);
var record = $copy(props.row || {}); const record = $copy(props.row || {});
async function update() { async function update() {
let data = $resetNull(record); let data = $resetNull(record);
let rs = data.id let rs = data.id

View File

@@ -212,24 +212,24 @@
@texteditor="updateText" @texteditor="updateText"
@update="updateAttr" @update="updateAttr"
v-if="showmodal" v-if="showmodal"
></Modal> />
</template> </template>
<script setup> <script setup>
const emit = defineEmits([]); const emit = defineEmits([]);
var props = defineProps({ const props = defineProps({
pagename: String, pagename: String,
row: Object, row: Object,
api: String, api: String,
}); });
const { $copy, $resetNull, $insertrow, $updaterow, $copyToClipboard, $empty } = useNuxtApp(); const { $copy, $resetNull, $insertrow, $updaterow, $copyToClipboard, $empty } = useNuxtApp();
var record = ref(props.row ? $copy(props.row) : {}); const record = ref(props.row ? $copy(props.row) : {});
var showmodal = ref(); const showmodal = ref();
var vapi = props.api; const vapi = props.api;
var current; let current;
var updateText = function (content) { function updateText(content) {
record.value.vi = content; record.value.vi = content;
}; }
var openEditor = function () { function openEditor() {
showmodal.value = { showmodal.value = {
component: "common/TextEditor", component: "common/TextEditor",
vbind: { content: record.value.vi }, vbind: { content: record.value.vi },
@@ -237,8 +237,8 @@ var openEditor = function () {
width: "40%", width: "40%",
height: "150px", height: "150px",
}; };
}; }
var editDetail = function (attr) { function editDetail(attr) {
current = attr; current = attr;
let detail = record.value[attr] ? record.value[attr] : {}; let detail = record.value[attr] ? record.value[attr] : {};
showmodal.value = { showmodal.value = {
@@ -248,10 +248,10 @@ var editDetail = function (attr) {
width: "40%", width: "40%",
height: "150px", height: "150px",
}; };
}; }
var updateAttr = function (detail) { function updateAttr(detail) {
record.value[current] = detail; record.value[current] = detail;
}; }
function copyDetail(attr) { function copyDetail(attr) {
if ($empty(record.value[attr])) return; if ($empty(record.value[attr])) return;
let val = typeof record.value[attr] == "string" ? record.value[attr] : JSON.stringify(record.value[attr]); let val = typeof record.value[attr] == "string" ? record.value[attr] : JSON.stringify(record.value[attr]);
@@ -262,7 +262,7 @@ async function pasteDetail(attr) {
if ($empty(text)) return; if ($empty(text)) return;
record.value[attr] = JSON.parse(text); record.value[attr] = JSON.parse(text);
} }
var updateData = async function (isNew) { async function updateData(isNew) {
let ele = record.value; let ele = record.value;
if (ele.create_time === null) ele.create_time = new Date(); if (ele.create_time === null) ele.create_time = new Date();
ele = $resetNull(ele); ele = $resetNull(ele);
@@ -271,5 +271,5 @@ var updateData = async function (isNew) {
? await $updaterow(vapi, ele, undefined, props.pagename) ? await $updaterow(vapi, ele, undefined, props.pagename)
: await $insertrow(vapi, ele, undefined, props.pagename); : await $insertrow(vapi, ele, undefined, props.pagename);
if (isNew) emit("close"); if (isNew) emit("close");
}; }
</script> </script>

View File

@@ -257,7 +257,7 @@ import InputEmail from "~/components/common/InputEmail";
import SearchBox from "~/components/SearchBox"; import SearchBox from "~/components/SearchBox";
import Datepicker from "~/components/datepicker/Datepicker"; import Datepicker from "~/components/datepicker/Datepicker";
var props = defineProps({ const props = defineProps({
pagename: String, pagename: String,
row: Object, row: Object,
}); });
@@ -277,29 +277,28 @@ const {
$updatepage, $updatepage,
} = useNuxtApp(); } = useNuxtApp();
const emit = defineEmits(["update"]); const emit = defineEmits(["update"]);
var viewport = store.viewport; const companyAddon = {
var companyAddon = {
component: "customer/Company", component: "customer/Company",
with: "55%", with: "55%",
height: "400px", height: "400px",
title: findLang("company"), title: findLang("company"),
}; };
var companyviewAddon = { const companyviewAddon = {
component: "customer/Company", component: "customer/Company",
width: "50%", width: "50%",
height: "400px", height: "400px",
title: findLang("company"), title: findLang("company"),
}; };
var errors = ref({}); const errors = ref({});
var record = ref(); const record = ref();
var showmodal = ref(); const showmodal = ref();
var existedPeople = undefined; let existedPeople = undefined;
async function initData() { async function initData() {
if (props.row) { if (props.row) {
let conn = $findapi("people"); const conn = $findapi("people");
conn.params.filter = { id: props.row.customer || props.row.id }; conn.params.filter = { id: props.row.customer || props.row.id };
let rs = await $getapi([conn]); const rs = await $getapi([conn]);
let found = $find(rs, { name: "people" }); const found = $find(rs, { name: "people" });
if (found.data.rows.length > 0) record.value = found.data.rows[0]; if (found.data.rows.length > 0) record.value = found.data.rows[0];
} else { } else {
// let code = await $getdata('getcodepeople') // let code = await $getdata('getcodepeople')
@@ -307,7 +306,7 @@ async function initData() {
} }
} }
function findLang(code) { function findLang(code) {
let found = $find(store.common, { code: code }); const found = $find(store.common, { code });
return found ? found[store.lang] : ""; return found ? found[store.lang] : "";
} }
function showPeople() { function showPeople() {

View File

@@ -176,7 +176,7 @@ export default defineNuxtPlugin((nuxtApp) => {
if (obj1[v] !== obj2[v]) change = true; if (obj1[v] !== obj2[v]) change = true;
}); });
} else { } else {
for (var k in obj1) { for (const k in obj1) {
if (obj1[k] !== obj2[k]) change = true; if (obj1[k] !== obj2[k]) change = true;
} }
} }
@@ -201,7 +201,7 @@ export default defineNuxtPlugin((nuxtApp) => {
// IE specific code path to prevent textarea being shown while dialog is visible. // IE specific code path to prevent textarea being shown while dialog is visible.
return clipboardData.setData("Text", text); return clipboardData.setData("Text", text);
} else if (document.queryCommandSupported && document.queryCommandSupported("copy")) { } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
var textarea = document.createElement("textarea"); const textarea = document.createElement("textarea");
textarea.textContent = text; textarea.textContent = text;
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in MS Edge. textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in MS Edge.
document.body.appendChild(textarea); document.body.appendChild(textarea);
@@ -308,9 +308,9 @@ export default defineNuxtPlugin((nuxtApp) => {
}; };
const vnmoney = function (amount) { const vnmoney = function (amount) {
var readGroup = function (group) { const readGroup = function (group) {
let readDigit = [" Không", " Một", " Hai", " Ba", " Bốn", " Năm", " Sáu", " Bảy", " Tám", " Chín"]; const readDigit = [" Không", " Một", " Hai", " Ba", " Bốn", " Năm", " Sáu", " Bảy", " Tám", " Chín"];
var temp = ""; let temp = "";
if (group == "000") return ""; if (group == "000") return "";
temp = readDigit[parseInt(group.substring(0, 1))] + " Trăm"; temp = readDigit[parseInt(group.substring(0, 1))] + " Trăm";
if (group.substring(1, 2) == "0") if (group.substring(1, 2) == "0")
@@ -324,8 +324,8 @@ export default defineNuxtPlugin((nuxtApp) => {
else if (group.substring(2, 3) != "0") temp += readDigit[parseInt(group.substring(2, 3))]; else if (group.substring(2, 3) != "0") temp += readDigit[parseInt(group.substring(2, 3))];
return temp; return temp;
}; };
var readMoney = function (num) { const readMoney = function (num) {
if (num == null || num == "") return ""; if ($empty(num)) return "";
let temp = ""; let temp = "";
while (num.length < 18) { while (num.length < 18) {
num = "0" + num; num = "0" + num;
@@ -450,22 +450,20 @@ export default defineNuxtPlugin((nuxtApp) => {
}; };
const numberToVietnamese = (input) => { const numberToVietnamese = (input) => {
if (input === null || input === undefined || input === "") return ""; if ($empty(input)) return "";
var number = Number(input); let number = Number(input);
if (isNaN(number) || number < 0 || number % 1 !== 0) return ""; if (isNaN(number) || number < 0 || number % 1 !== 0) return "";
if (number === 0) return "Không"; if (number === 0) return "Không";
var units = ["không", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín"]; const units = ["không", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín"];
const scales = ["", "nghìn", "triệu", "tỷ", "nghìn tỷ", "triệu tỷ"];
var scales = ["", "nghìn", "triệu", "tỷ", "nghìn tỷ", "triệu tỷ"];
function readThreeDigits(num, isFull) { function readThreeDigits(num, isFull) {
var result = ""; let result = "";
var hundred = Math.floor(num / 100); const hundred = Math.floor(num / 100);
var ten = Math.floor((num % 100) / 10); const ten = Math.floor((num % 100) / 10);
var unit = num % 10; const unit = num % 10;
if (hundred > 0 || isFull) { if (hundred > 0 || isFull) {
result += units[hundred] + " trăm"; result += units[hundred] + " trăm";
@@ -488,14 +486,14 @@ export default defineNuxtPlugin((nuxtApp) => {
return result.trim(); return result.trim();
} }
var result = ""; let result = "";
var scaleIndex = 0; let scaleIndex = 0;
while (number > 0) { while (number > 0) {
var chunk = number % 1000; let chunk = number % 1000;
if (chunk > 0) { if (chunk > 0) {
var isFull = result !== ""; const isFull = result !== "";
result = result =
readThreeDigits(chunk, isFull) + readThreeDigits(chunk, isFull) +
(scales[scaleIndex] ? " " + scales[scaleIndex] : "") + (scales[scaleIndex] ? " " + scales[scaleIndex] : "") +

View File

@@ -186,8 +186,8 @@ export default defineNuxtPlugin((nuxtApp) => {
}; };
const findpage = function (arr) { const findpage = function (arr) {
var copy = $copy(store.pagetrack); const copy = $copy(store.pagetrack);
var doFind = function () { function doFind() {
let found = undefined; let found = undefined;
for (let i = 1; i <= 30; i++) { for (let i = 1; i <= 30; i++) {
let name = `pagedata${i}`; let name = `pagedata${i}`;
@@ -199,7 +199,7 @@ export default defineNuxtPlugin((nuxtApp) => {
} }
if (!found) console.log("pagename not found"); if (!found) console.log("pagename not found");
return found; return found;
}; }
let result; let result;
if (arr) { if (arr) {
result = []; result = [];