346 lines
10 KiB
Vue
346 lines
10 KiB
Vue
<script setup lang="ts">
|
|
import { createResourceBatch, getInfoPriceBook } from '#/api/database/info';
|
|
import { DbHst } from '#/components/db-hst';
|
|
import { DbTree } from '#/components/db-tree';
|
|
import { useUpload } from '#/components/upload/use-upload';
|
|
import { Page } from '@vben/common-ui';
|
|
import { IconifyIcon } from '@vben/icons';
|
|
import { useAccessStore } from '@vben/stores';
|
|
import { useElementSize } from '@vueuse/core';
|
|
import type { UploadProps } from 'element-plus';
|
|
import { ElButton, ElCard, ElDialog, ElImage, ElInput, ElMessage, ElSplitter, ElSplitterPanel, ElText, ElUpload } from 'element-plus';
|
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
|
import { useRoute } from 'vue-router';
|
|
import { HistoryDialog } from '../components/history-dialog';
|
|
import { MorePriceDialog } from '../components/more-price-dialog';
|
|
import { useDbHst } from './dbHst';
|
|
import { useDbTree } from './dbTree';
|
|
|
|
const route = useRoute();
|
|
const accessStore = useAccessStore();
|
|
|
|
const { uploadUrl, httpRequest } = useUpload('info-price');
|
|
|
|
const bookId = ref<any>(null);
|
|
const currentCategoryTreeId = ref<any>(null);
|
|
const bookTitle = ref<string>('');
|
|
const bookInfo = ref<any>(null);
|
|
|
|
const containerRef = ref<HTMLElement | null>(null);
|
|
const { height: containerHeight } = useElementSize(containerRef);
|
|
|
|
const isCcompleted = computed(() => accessStore.tenantId != 1 && bookInfo.value?.publishStatus === 'completed');
|
|
|
|
const dbTreeRef = ref();
|
|
const hstRef = ref();
|
|
|
|
const previewImageUrl = ref<string>('');
|
|
const previewVisible = ref(false);
|
|
const uploadDialogVisible = ref(false);
|
|
const currentUploadRow = ref<number>(0);
|
|
const currentUploadCol = ref<number>(0);
|
|
const uploadImageUrl = ref<string>('');
|
|
const uploading = ref(false);
|
|
|
|
const morePriceDialogVisible = ref(false);
|
|
const currentPriceRow = ref<number>(0);
|
|
const selectRowPrice = ref<any>(null);
|
|
|
|
const historyDialogVisible = ref(false);
|
|
const categorySource = ref<{ label: string; value: any }[]>([]);
|
|
const search = ref();
|
|
|
|
const handlePhotoPreview = (value: string) => {
|
|
previewImageUrl.value = value;
|
|
previewVisible.value = true;
|
|
};
|
|
|
|
const handlePhotoUpload = (row: number, col: number, value: string) => {
|
|
currentUploadRow.value = row;
|
|
currentUploadCol.value = col;
|
|
uploadImageUrl.value = value;
|
|
uploadDialogVisible.value = true;
|
|
};
|
|
|
|
const handleShowMorePrice = (row: number, col: number, value: any) => {
|
|
currentPriceRow.value = row;
|
|
morePriceDialogVisible.value = true;
|
|
selectRowPrice.value = hstRef.value.hotInstance.getSourceDataAtRow(row);
|
|
console.log('查看更多单价:', { row, col, value }, selectRowPrice.value);
|
|
};
|
|
|
|
const callbacks = {
|
|
onPhotoPreview: handlePhotoPreview,
|
|
onPhotoUpload: handlePhotoUpload,
|
|
onShowMorePrice: handleShowMorePrice,
|
|
};
|
|
|
|
const {
|
|
columns,
|
|
contextMenuItems,
|
|
dbSettings,
|
|
loadResourcePage,
|
|
loadCategorySource,
|
|
updateCategoryColumnSource,
|
|
} = useDbHst(hstRef, bookId, currentCategoryTreeId, isCcompleted, callbacks);
|
|
|
|
const {
|
|
treeData,
|
|
rootMenus,
|
|
nodeMenus,
|
|
loadCategoryTree,
|
|
handleTreeNodeSelect,
|
|
handleTreeNodeEdit,
|
|
} = useDbTree(dbTreeRef, bookId, isCcompleted, currentCategoryTreeId, loadResourcePage);
|
|
|
|
const loadBookInfo = async () => {
|
|
if (!bookId.value) return;
|
|
|
|
try {
|
|
const res = await getInfoPriceBook(bookId.value);
|
|
if (res) {
|
|
bookInfo.value = res;
|
|
bookTitle.value = `${res.name} (${res.startTime} ~ ${res.endTime})`;
|
|
}
|
|
} catch (error) {
|
|
console.error('加载信息价册失败:', error);
|
|
}
|
|
};
|
|
|
|
const handleSelectPrice = async (row: any) => {
|
|
if (hstRef.value?.hotInstance && selectRowPrice.value) {
|
|
const sendData = {
|
|
...selectRowPrice.value,
|
|
priceTaxExcl: row.priceTaxExcl,
|
|
taxRate: row.taxRate,
|
|
priceTaxIncl: row.priceTaxIncl,
|
|
};
|
|
|
|
try {
|
|
await createResourceBatch([sendData]);
|
|
ElMessage.success('更新成功');
|
|
loadResourcePage();
|
|
} catch (error) {
|
|
console.error('更新失败:', error);
|
|
ElMessage.error('更新失败');
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleHistoryConfirm = async (nodes: any[]) => {
|
|
if (!nodes || nodes.length === 0) {
|
|
ElMessage.warning('请选择要导入的数据');
|
|
return;
|
|
}
|
|
|
|
const updatedNodes = nodes.map(node => ({
|
|
...node,
|
|
categoryTreeId: currentCategoryTreeId.value,
|
|
resourceItemId: node.id,
|
|
id: null,
|
|
}));
|
|
|
|
const res = await createResourceBatch(updatedNodes);
|
|
if (hstRef.value?.hotInstance && res) {
|
|
loadResourcePage();
|
|
ElMessage.success(`成功导入 ${updatedNodes.length} 条数据`);
|
|
}
|
|
};
|
|
|
|
const handleBeforeUpload: UploadProps['beforeUpload'] = rawFile => {
|
|
if (!rawFile.type.startsWith('image/')) {
|
|
ElMessage.error('只能上传图片文件!');
|
|
return false;
|
|
}
|
|
if (rawFile.size / 1024 / 1024 > 5) {
|
|
ElMessage.error('图片大小不能超过 5MB!');
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
const handleHttpRequest = (options: any) => {
|
|
uploading.value = true;
|
|
return httpRequest(options.file);
|
|
};
|
|
|
|
const handleUploadSuccess: UploadProps['onSuccess'] = (response: any) => {
|
|
uploading.value = false;
|
|
const imageUrl = response?.url || response;
|
|
uploadImageUrl.value = imageUrl;
|
|
|
|
if (hstRef.value?.hotInstance) {
|
|
hstRef.value.hotInstance.setDataAtCell(currentUploadRow.value, currentUploadCol.value, imageUrl);
|
|
}
|
|
ElMessage.success('上传成功');
|
|
handleDialogClose();
|
|
};
|
|
|
|
const handleUploadError: UploadProps['onError'] = () => {
|
|
uploading.value = false;
|
|
ElMessage.error('上传失败,请重试');
|
|
};
|
|
|
|
const handleUploadChange: UploadProps['onChange'] = uploadFile => {
|
|
if (uploadFile.raw) {
|
|
uploadImageUrl.value = URL.createObjectURL(uploadFile.raw);
|
|
}
|
|
};
|
|
|
|
const handleDialogClose = () => {
|
|
uploadDialogVisible.value = false;
|
|
};
|
|
|
|
const handlePreviewClose = () => {
|
|
previewVisible.value = false;
|
|
previewImageUrl.value = '';
|
|
};
|
|
|
|
const handleQuery = () => {
|
|
console.log('handleQuery');
|
|
};
|
|
|
|
const handleOpenHistoryDialog = () => {
|
|
if (!currentCategoryTreeId.value) {
|
|
ElMessage.warning('请先选择左侧分类节点');
|
|
return;
|
|
}
|
|
historyDialogVisible.value = true;
|
|
};
|
|
|
|
onMounted(async () => {
|
|
bookId.value = route.params.id || route.query.id;
|
|
await loadBookInfo();
|
|
await loadCategoryTree();
|
|
categorySource.value = await loadCategorySource();
|
|
updateCategoryColumnSource(categorySource.value);
|
|
|
|
nextTick(() => {
|
|
if (hstRef.value?.hotInstance) {
|
|
if (accessStore.tenantId != 1) {
|
|
const editableColumns = ['priceTaxExcl', 'taxRate', 'priceTaxIncl'];
|
|
const updatedColumns = columns.map(col => ({
|
|
...col,
|
|
editor: editableColumns.includes(col.data) ? col.editor : false,
|
|
}));
|
|
hstRef.value.hotInstance.updateSettings({
|
|
columns: updatedColumns,
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Page auto-content-height>
|
|
<ElCard class="h-full w-full border-radius-0" body-class="!p-0 h-full w-full flex flex-col" header-class="!p-1">
|
|
<div class="!p-1">
|
|
<ElText class="mx-1">信息价名称: {{ bookTitle }}</ElText>
|
|
<ElInput
|
|
v-model="search"
|
|
style="width: 300px"
|
|
placeholder="请输入"
|
|
class="input-with-select"
|
|
size="small"
|
|
>
|
|
<template #append>
|
|
<ElButton @click="handleQuery" size="small"><IconifyIcon icon="ep:search" /></ElButton>
|
|
</template>
|
|
</ElInput>
|
|
<ElButton
|
|
@click="handleOpenHistoryDialog"
|
|
type="primary"
|
|
size="small"
|
|
style="float: right"
|
|
:disabled="isCcompleted"
|
|
>
|
|
调用历史信息
|
|
</ElButton>
|
|
</div>
|
|
<div class="h-full w-full" ref="containerRef">
|
|
<ElSplitter :style="{ height: containerHeight + 'px' }">
|
|
<ElSplitterPanel size="15%" :min="200">
|
|
<ElCard class="w-full h-full border-radius-0" body-class="!p-0 h-full w-full flex flex-col">
|
|
<DbTree
|
|
ref="dbTreeRef"
|
|
:tree-data="treeData"
|
|
:root-menus="rootMenus"
|
|
:node-menus="nodeMenus"
|
|
@node-edit="handleTreeNodeEdit"
|
|
@node-click="handleTreeNodeSelect"
|
|
:defaultExpandedLevel="4"
|
|
/>
|
|
</ElCard>
|
|
</ElSplitterPanel>
|
|
<ElSplitterPanel :min="200">
|
|
<ElCard class="w-full h-full border-radius-0" body-class="!p-0 h-full w-full flex flex-col">
|
|
<DbHst ref="hstRef" :settings="dbSettings" :contextMenuItems="contextMenuItems" />
|
|
</ElCard>
|
|
</ElSplitterPanel>
|
|
</ElSplitter>
|
|
</div>
|
|
</ElCard>
|
|
|
|
<HistoryDialog
|
|
v-model:visible="historyDialogVisible"
|
|
:bookInfo="bookInfo"
|
|
:categorySource="categorySource"
|
|
@confirm="handleHistoryConfirm"
|
|
/>
|
|
|
|
<ElDialog v-model="uploadDialogVisible" title="上传图片" width="500px" @close="handleDialogClose">
|
|
<div class="upload-container">
|
|
<ElUpload
|
|
class="upload-demo"
|
|
drag
|
|
:action="uploadUrl"
|
|
:http-request="handleHttpRequest"
|
|
:show-file-list="false"
|
|
:before-upload="handleBeforeUpload"
|
|
:on-success="handleUploadSuccess"
|
|
:on-error="handleUploadError"
|
|
:on-change="handleUploadChange"
|
|
accept="image/*"
|
|
:disabled="uploading"
|
|
>
|
|
<div class="flex min-h-[200px] flex-col items-center justify-center py-8">
|
|
<span class="icon-[mdi--cloud-upload-outline] mb-4 text-6xl text-gray-400"></span>
|
|
<div class="text-base text-gray-600">点击或拖拽文件到此区域上传</div>
|
|
<div class="mt-2 text-sm text-gray-400">支持 .jpg、.png、.gif、.webp 格式图片文件</div>
|
|
</div>
|
|
</ElUpload>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<ElButton @click="handleDialogClose" :disabled="uploading">关闭</ElButton>
|
|
</template>
|
|
</ElDialog>
|
|
|
|
<ElDialog v-model="previewVisible" title="图片预览" width="800px" @close="handlePreviewClose">
|
|
<div class="preview-image-container">
|
|
<ElImage
|
|
:src="previewImageUrl"
|
|
fit="contain"
|
|
:preview-src-list="[previewImageUrl]"
|
|
:initial-index="0"
|
|
style="width: 100%; max-height: 600px"
|
|
/>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<ElButton @click="handlePreviewClose">关闭</ElButton>
|
|
</template>
|
|
</ElDialog>
|
|
|
|
<MorePriceDialog
|
|
v-model:visible="morePriceDialogVisible"
|
|
:bookInfo="bookInfo"
|
|
:selectRowPrice="selectRowPrice"
|
|
@select="handleSelectPrice"
|
|
/>
|
|
</Page>
|
|
</template>
|
|
|
|
<style lang="css"></style>
|