This commit is contained in:
Viet An
2026-05-21 11:42:36 +07:00
parent 8f95fee8a7
commit 80f1e7275f
10 changed files with 158 additions and 59 deletions

View File

@@ -2,7 +2,10 @@
<span :class="`icon-text is-flex-wrap-nowrap font-semibold fs-${props.size || 15} ${props.type || ''}`"> <span :class="`icon-text is-flex-wrap-nowrap font-semibold fs-${props.size || 15} ${props.type || ''}`">
<span style="text-wrap: nowrap">{{ title }}</span> <span style="text-wrap: nowrap">{{ title }}</span>
<span class="icon"> <span class="icon">
<Icon name="material-symbols:arrow-forward-ios-rounded" /> <Icon
name="material-symbols:arrow-forward-ios-rounded"
:size="13"
/>
</span> </span>
</span> </span>
</template> </template>

View File

@@ -3,7 +3,7 @@ const props = defineProps({
text: String, text: String,
image: String, image: String,
type: String, type: String,
size: Number, size: String,
}); });
</script> </script>
<template> <template>

View File

@@ -131,7 +131,7 @@
<p class="control"> <p class="control">
<button <button
class="button is-light is-primary" class="button is-light is-primary"
@click="currentField.mandatory ? false : doRemove()" @click="!currentField.mandatory && doRemove()"
> >
<span class="icon"> <span class="icon">
<Icon <Icon
@@ -149,10 +149,8 @@
<p class="control"> <p class="control">
<button <button
class="button is-light is-primary" class="button is-light is-primary"
:class="currentField.format === 'number' ? null : 'has-text-grey-light'" :class="currentField.format !== 'number' && 'has-text-grey-light'"
@click=" @click="currentField.format === 'number' && $emit('modalevent', { name: 'copyfield', data: currentField })"
currentField.format === 'number' ? $emit('modalevent', { name: 'copyfield', data: currentField }) : false
"
> >
<span class="icon"> <span class="icon">
<Icon <Icon
@@ -310,10 +308,11 @@
</div> </div>
<div class="field"> <div class="field">
<label class="label fs-14">Kiểu dữ liệu<span class="has-text-danger"> * </span></label> <label class="label fs-14">Kiểu dữ liệu<span class="has-text-danger"> * </span></label>
<div class="control fs-14"> <div class="control is-flex is-gap-0.5">
<button <button
v-for="v in datatype" v-for="(v, i) in datatype"
class="button is-white fs-14" :key="i"
:class="['button fs-14', radioType === v ? 'is-primary is-light' : 'is-white']"
> >
<span class="icon"> <span class="icon">
<Icon <Icon
@@ -372,11 +371,12 @@
<div class="field"> <div class="field">
<div class="field"> <div class="field">
<label class="label fs-14">Định dạng nâng cao</label> <label class="label fs-14">Định dạng nâng cao</label>
<div class="control"> <div class="control is-flex is-gap-0.5">
<button <button
v-for="v in colorchoice.filter((v) => v.code !== 'condition')" v-for="(v, i) in colorchoice.filter((v) => v.code !== 'condition')"
:key="i"
@click="changeTemplate(v)" @click="changeTemplate(v)"
class="button is-white fs-14" :class="['button fs-14', radioTemplate === v.code ? 'is-primary is-light' : 'is-white']"
> >
<span class="icon"> <span class="icon">
<Icon <Icon
@@ -392,10 +392,16 @@
</button> </button>
<button <button
v-if="radioTemplate === 'option'" v-if="radioTemplate === 'option'"
class="button is-primary is-light fs-14 ml-2" class="button is-primary is-outlined fs-14 ml-2"
@click="showSidebar()" @click="showSidebar()"
> >
{{ currentField.template ? "Sửa" : "Tạo" }} định dạng <span class="icon">
<Icon
:name="currentField.template ? 'material-symbols:edit-outline-rounded' : 'material-symbols:add-rounded'"
:size="17"
/>
</span>
<span>{{ currentField.template ? "Sửa" : "Tạo" }} định dạng</span>
</button> </button>
</div> </div>
</div> </div>
@@ -408,6 +414,7 @@
name: props.field.name, name: props.field.name,
maxHeight: '380px', maxHeight: '380px',
perpage: 20, perpage: 20,
inContext: true,
}" }"
@selected="doSelect" @selected="doSelect"
/> />
@@ -422,7 +429,7 @@
</template> </template>
<script setup> <script setup>
import { useStore } from "@/stores/index"; import { useStore } from "@/stores/index";
import ScrollBox from "~/components/datatable/ScrollBox"; import ScrollBox from "@/components/datatable/ScrollBox.vue";
const store = useStore(); const store = useStore();
const { $copy, $stripHtml, $clone, $arrayMove, $snackbar, $copyToClipboard } = useNuxtApp(); const { $copy, $stripHtml, $clone, $arrayMove, $snackbar, $copyToClipboard } = useNuxtApp();
var props = defineProps({ var props = defineProps({
@@ -645,4 +652,15 @@ p.control {
width: 100%; width: 100%;
} }
} }
.tabs {
--bulma-tabs-toggle-link-active-background-color: var(--bulma-link-90);
--bulma-tabs-toggle-link-active-border-color: var(--bulma-link-90);
--bulma-tabs-toggle-link-active-color: var(--bulma-link-25);
}
.button.is-primary.is-outlined:hover {
--bulma-button-border-width: max(1px, 0.0625em); /* same as not-hovered */
background-color: var(--bulma-primary-95);
}
</style> </style>

View File

@@ -355,7 +355,7 @@
</div> </div>
</template> </template>
<template v-else-if="tab.code === 'template'"> <template v-else-if="tab.code === 'template'">
<div class="buttons mb-3"> <div class="buttons has-addons mb-3">
<button <button
@click="copyContent()" @click="copyContent()"
class="button is-primary is-light fs-14" class="button is-primary is-light fs-14"

View File

@@ -415,7 +415,7 @@ const getApi = async () => {
const dataEvent = (v, field, data) => { const dataEvent = (v, field, data) => {
if (data?.modal) { if (data?.modal) {
const copy = $copy(data.modal); const copy = $copy(data.modal);
const f = copy.vbind ? copy.vbind : {}; const f = copy.vbind ?? {};
if (!f.api) f.api = props.api; if (!f.api) f.api = props.api;
f.pagename = vpagename; f.pagename = vpagename;
if (!f.row) f.row = v; if (!f.row) f.row = v;
@@ -423,7 +423,7 @@ const dataEvent = (v, field, data) => {
copy.field = field; copy.field = field;
showmodal.value = copy; showmodal.value = copy;
} }
emit("modalevent", { name: "dataevent", data: { row: v, field: field } }); emit("modalevent", { name: "dataevent", data: { row: v, field } });
emit("dataevent", v, field); emit("dataevent", v, field);
}; };

View File

@@ -1,14 +1,97 @@
<template> <template>
<div <div
:style="{ :style="{ maxHeight, overflowY: 'auto' }"
maxHeight, @scroll="handleScroll"
overflowY: 'auto',
}"
> >
<table
v-if="inContext"
class="table is-bordered is-hoverable is-fullwidth"
>
<tbody>
<tr
v-for="(v, i) in rows"
:key="i"
@click="doClick(v, i)"
class="fs-14 is-clickable"
>
<td>
<span>{{ $stripHtml(v[name] || v.fullname || v.code || "n/a", 75) }}</span>
<span
v-if="checked[i] && notick !== true"
class="icon right-3"
>
<Icon
name="material-symbols:check-rounded"
:size="17"
class="has-text-primary"
/>
</span>
</td>
<p
class="control py-0"
v-if="show"
>
<span
class="icon-text has-text-grey mr-2 fs-13"
v-if="show.author"
>
<SvgIcon v-bind="{ name: 'user.svg', type: 'gray', size: 15 }"></SvgIcon>
<span>{{ v[show.author] }}</span>
</span>
<span
class="icon-text has-text-grey mr-2 fs-13"
v-if="show.view"
>
<SvgIcon v-bind="{ name: 'view.svg', type: 'gray', size: 15 }"></SvgIcon>
<span>{{ v[show.view] }}</span>
</span>
<span
class="fs-13 has-text-grey"
v-if="show.time"
>{{ $dayjs(v["create_time"]).fromNow(true) }}</span
>
<span class="tooltip">
<a
class="icon ml-1"
v-if="show.link"
@click="doClick(v, i, 'newtab')"
>
<SvgIcon v-bind="{ name: 'opennew.svg', type: 'gray', size: 15 }"></SvgIcon>
</a>
<span class="tooltiptext">Mở trong tab mớ</span>
</span>
<span
class="tooltip"
v-if="show.rename"
>
<a
class="icon ml-1"
@click="$emit('rename', v, i)"
>
<SvgIcon v-bind="{ name: 'pen1.svg', type: 'gray', size: 15 }"></SvgIcon>
</a>
<span class="tooltiptext">Đổi tên</span>
</span>
<span
class="tooltip"
v-if="show.rename"
>
<a
class="icon has-text-danger ml-1"
@click="$emit('remove', v, i)"
>
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'gray', size: 15 }"></SvgIcon>
</a>
<span class="tooltiptext">Xóa</span>
</span>
</p>
</tr>
</tbody>
</table>
<div <div
v-else
v-for="(v, i) in rows" v-for="(v, i) in rows"
:key="i" :key="i"
class=""
> >
<button <button
class="button is-white rounded-none fs-14 font-normal w-full is-justify-content-space-between" class="button is-white rounded-none fs-14 font-normal w-full is-justify-content-space-between"
@@ -99,6 +182,7 @@ const props = defineProps({
keyval: String, keyval: String,
show: Object, show: Object,
notick: Boolean, notick: Boolean,
inContext: Boolean,
}); });
const emit = defineEmits(["selected"]); const emit = defineEmits(["selected"]);

View File

@@ -2,19 +2,23 @@
const props = defineProps({ const props = defineProps({
variant: Object, variant: Object,
}); });
const showModal = ref(null);
</script> </script>
<template> <template>
<a <a
@click=" @click="
showModal = { $emit('clickevent', {
component: 'imports/EditProduct', name: 'dataevent',
title: 'Cập nhật sản phẩm', data: {
width: '90%', modal: {
height: '400px', title: 'Cập nhật sản phẩm',
vbind: { variant: props.variant }, width: '90%',
} height: '400px',
component: 'imports/EditProduct',
vbind: { variant: props.variant },
},
},
})
" "
> >
<span class="icon"> <span class="icon">
@@ -24,9 +28,4 @@ const showModal = ref(null);
/> />
</span> </span>
</a> </a>
<Modal
v-if="showModal"
v-bind="showModal"
@close="showModal = null"
/>
</template> </template>

View File

@@ -2,32 +2,30 @@
const props = defineProps({ const props = defineProps({
variant: Object, variant: Object,
}); });
const showModal = ref(null);
</script> </script>
<template> <template>
<button <a
@click=" @click="
showModal = { $emit('clickevent', {
component: 'imports/IMEIs', name: 'dataevent',
title: 'IMEIs', data: {
width: '80%', modal: {
height: '400px', component: 'imports/IMEIs',
vbind: { variant: props.variant }, title: 'IMEIs',
} width: '80%',
height: '400px',
vbind: { variant: props.variant },
},
},
})
" "
class="button is-small is-primary is-ghost"
> >
<span class="icon"> <span class="icon">
<Icon <Icon
name="mdi:launch" name="mdi:launch"
:size="22" :size="18"
/> />
</span> </span>
</button> </a>
<Modal
v-if="showModal"
v-bind="showModal"
@close="showModal = null"
/>
</template> </template>

View File

@@ -6,7 +6,7 @@
<SvgIcon v-bind="{ name: 'pen1.svg', type: 'dark', size: 16 }"></SvgIcon> <SvgIcon v-bind="{ name: 'pen1.svg', type: 'dark', size: 16 }"></SvgIcon>
</a> </a>
<a <a
@click="remove()" @click="$emit('remove')"
v-if="attrs.onRemove" v-if="attrs.onRemove"
> >
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'dark', size: 16 }"></SvgIcon> <SvgIcon v-bind="{ name: 'bin1.svg', type: 'dark', size: 16 }"></SvgIcon>
@@ -16,7 +16,4 @@
import { useAttrs } from "vue"; import { useAttrs } from "vue";
const attrs = useAttrs(); const attrs = useAttrs();
const emit = defineEmits(["edit", "remove"]); const emit = defineEmits(["edit", "remove"]);
const remove = function () {
emit("remove");
};
</script> </script>

View File

@@ -15,7 +15,7 @@
<span>{{ tab[$store.lang] }}</span> <span>{{ tab[$store.lang] }}</span>
<Icon <Icon
name="material-symbols:arrow-forward-ios-rounded" name="material-symbols:arrow-forward-ios-rounded"
:size="15" :size="13"
class="has-text-grey" class="has-text-grey"
/> />
<span>{{ subtab[$store.lang] }}</span> <span>{{ subtab[$store.lang] }}</span>