refactor: view image dialog
This commit is contained in:
parent
bfe5da2565
commit
718a28642d
3 changed files with 126 additions and 1 deletions
|
|
@ -6,7 +6,11 @@ import { storeToRefs } from 'pinia';
|
||||||
import WorkerItem from './WorkerItem.vue';
|
import WorkerItem from './WorkerItem.vue';
|
||||||
import DeleteButton from '../button/DeleteButton.vue';
|
import DeleteButton from '../button/DeleteButton.vue';
|
||||||
import { precisionRound } from 'src/utils/arithmetic';
|
import { precisionRound } from 'src/utils/arithmetic';
|
||||||
import { ProductServiceList, QuotationPayload } from 'stores/quotations/types';
|
import {
|
||||||
|
ProductRelation,
|
||||||
|
ProductServiceList,
|
||||||
|
QuotationPayload,
|
||||||
|
} from 'stores/quotations/types';
|
||||||
import { formatNumberDecimal, commaInput } from 'stores/utils';
|
import { formatNumberDecimal, commaInput } from 'stores/utils';
|
||||||
import { useConfigStore } from 'stores/config';
|
import { useConfigStore } from 'stores/config';
|
||||||
|
|
||||||
|
|
@ -29,6 +33,7 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
|
(e: 'viewFile', data: ProductRelation): void;
|
||||||
(e: 'delete', index: number): void;
|
(e: 'delete', index: number): void;
|
||||||
(
|
(
|
||||||
e: 'updateTable',
|
e: 'updateTable',
|
||||||
|
|
@ -449,6 +454,7 @@ watch(
|
||||||
background-color: hsla(var(--positive-bg) / 0.1);
|
background-color: hsla(var(--positive-bg) / 0.1);
|
||||||
color: hsl(var(--positive-bg));
|
color: hsl(var(--positive-bg));
|
||||||
"
|
"
|
||||||
|
@click="$emit('viewFile', props.row.product)"
|
||||||
/>
|
/>
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
v-if="!readonly"
|
v-if="!readonly"
|
||||||
|
|
|
||||||
99
src/components/dialog/DialogViewFile.vue
Normal file
99
src/components/dialog/DialogViewFile.vue
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
import DialogFormContainer from './DialogFormContainer.vue';
|
||||||
|
import DialogHeader from './DialogHeader.vue';
|
||||||
|
import MainButton from '../button/MainButton.vue';
|
||||||
|
import NoData from '../NoData.vue';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
title: string;
|
||||||
|
url?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const open = defineModel<boolean>({ default: false });
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
imageZoom: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
state.imageZoom = 100;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<DialogFormContainer v-model="open" v-on:open="openDialog">
|
||||||
|
<template #header>
|
||||||
|
<DialogHeader :title="title" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<main class="column full-height">
|
||||||
|
<section
|
||||||
|
style="background: var(--gray-3)"
|
||||||
|
class="q-py-sm row justify-center"
|
||||||
|
>
|
||||||
|
<div class="surface-2 q-px-md q-py-sm rounded row no-wrap items-center">
|
||||||
|
<MainButton
|
||||||
|
icon="mdi-minus"
|
||||||
|
color="0 0% 0%"
|
||||||
|
icon-only
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (state.imageZoom > 0) state.imageZoom -= 10;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
class="q-px-sm"
|
||||||
|
input-class="text-center text-caption"
|
||||||
|
:model-value="state.imageZoom"
|
||||||
|
@update:model-value="
|
||||||
|
(val) => {
|
||||||
|
const numVal = Number(val);
|
||||||
|
if (numVal > 500 || numVal < 0) {
|
||||||
|
state.imageZoom = 100;
|
||||||
|
} else {
|
||||||
|
state.imageZoom = numVal || 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
></q-input>
|
||||||
|
<MainButton
|
||||||
|
icon="mdi-plus"
|
||||||
|
color="0 0% 0%"
|
||||||
|
icon-only
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (state.imageZoom < 500) state.imageZoom += 10;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:class="{ 'cursor-pointer': state.imageZoom > 100 }"
|
||||||
|
class="full-height full-width flex justify-center items-center col scroll q-pa-md"
|
||||||
|
v-dragscroll
|
||||||
|
>
|
||||||
|
<q-img
|
||||||
|
v-if="url"
|
||||||
|
class="full-height"
|
||||||
|
:src="url"
|
||||||
|
fit="contain"
|
||||||
|
:style="{ transform: `scale(${state.imageZoom / 100})` }"
|
||||||
|
style="transform-origin: 0 0"
|
||||||
|
/>
|
||||||
|
<NoData v-else />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</DialogFormContainer>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
:deep(.q-field__control.relative-position.row.no-wrap) {
|
||||||
|
width: 60px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -29,6 +29,7 @@ import { View } from './types.ts';
|
||||||
import {
|
import {
|
||||||
EmployeeWorker,
|
EmployeeWorker,
|
||||||
PayCondition,
|
PayCondition,
|
||||||
|
ProductRelation,
|
||||||
ProductServiceList,
|
ProductServiceList,
|
||||||
QuotationPayload,
|
QuotationPayload,
|
||||||
} from 'src/stores/quotations/types';
|
} from 'src/stores/quotations/types';
|
||||||
|
|
@ -64,6 +65,7 @@ import QuotationFormInfo from './QuotationFormInfo.vue';
|
||||||
import QuotationFormWorkerSelect from './QuotationFormWorkerSelect.vue';
|
import QuotationFormWorkerSelect from './QuotationFormWorkerSelect.vue';
|
||||||
import QuotationFormWorkerAddDialog from './QuotationFormWorkerAddDialog.vue';
|
import QuotationFormWorkerAddDialog from './QuotationFormWorkerAddDialog.vue';
|
||||||
import UploadFileSection from 'src/components/upload-file/UploadFileSection.vue';
|
import UploadFileSection from 'src/components/upload-file/UploadFileSection.vue';
|
||||||
|
import DialogViewFile from 'src/components/dialog/DialogViewFile.vue';
|
||||||
|
|
||||||
import { columnPaySplit } from './constants';
|
import { columnPaySplit } from './constants';
|
||||||
import { precisionRound } from 'src/utils/arithmetic';
|
import { precisionRound } from 'src/utils/arithmetic';
|
||||||
|
|
@ -291,6 +293,9 @@ const pageState = reactive({
|
||||||
employeeModal: false,
|
employeeModal: false,
|
||||||
productServiceModal: false,
|
productServiceModal: false,
|
||||||
remarkWrite: true,
|
remarkWrite: true,
|
||||||
|
imageDialog: false,
|
||||||
|
imageDialogTitle: '',
|
||||||
|
imageDialogUrl: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const productList = ref<Partial<Record<ProductGroupId, Product[]>>>({});
|
const productList = ref<Partial<Record<ProductGroupId, Product[]>>>({});
|
||||||
|
|
@ -956,6 +961,14 @@ async function uploadAttachment(file?: File) {
|
||||||
if (ret) await getAttachment();
|
if (ret) await getAttachment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function viewProductFile(data: ProductRelation) {
|
||||||
|
const base64 = data.detail.match(/src="([^"]+)"/);
|
||||||
|
|
||||||
|
pageState.imageDialog = true;
|
||||||
|
pageState.imageDialogTitle = data.name;
|
||||||
|
pageState.imageDialogUrl = base64 ? base64[1] : '';
|
||||||
|
}
|
||||||
|
|
||||||
const sessionData = ref<Record<string, any>>();
|
const sessionData = ref<Record<string, any>>();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|
@ -1539,6 +1552,7 @@ watch(
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
@update-table="handleUpdateProductTable"
|
@update-table="handleUpdateProductTable"
|
||||||
|
@view-file="viewProductFile"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|
@ -2262,6 +2276,12 @@ watch(
|
||||||
fetchQuotation();
|
fetchQuotation();
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<DialogViewFile
|
||||||
|
:title="pageState.imageDialogTitle"
|
||||||
|
:url="pageState.imageDialogUrl"
|
||||||
|
v-model="pageState.imageDialog"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue