|
|
@@ -0,0 +1,375 @@
|
|
|
+<script lang="ts" setup>
|
|
|
+import type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';
|
|
|
+
|
|
|
+import { ref } from 'vue';
|
|
|
+
|
|
|
+import { useVbenModal } from '@vben/common-ui';
|
|
|
+import { MdiMagnify } from '@vben/icons';
|
|
|
+import { useUserStore } from '@vben/stores';
|
|
|
+
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+
|
|
|
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
|
|
+import { editProductApi, getProductAndScqyListApi } from '#/api/product';
|
|
|
+
|
|
|
+import Form from './form.vue';
|
|
|
+
|
|
|
+const emit = defineEmits<{
|
|
|
+ finish: [];
|
|
|
+}>();
|
|
|
+
|
|
|
+// 获取用户信息
|
|
|
+const userStore = useUserStore();
|
|
|
+
|
|
|
+// 新增关联相关状态
|
|
|
+const selectedProduct = ref<any>(null);
|
|
|
+const addLinkLoading = ref(false);
|
|
|
+const searchKeyword = ref<string>('');
|
|
|
+const linkedProductIds = ref<string[]>([]);
|
|
|
+const showUnlinkedOnly = ref<boolean>(true);
|
|
|
+
|
|
|
+// 新增产品表单引用
|
|
|
+const formRef = ref();
|
|
|
+
|
|
|
+// 新增关联表格配置
|
|
|
+const addLinkGridOptions: VxeGridProps<any> = {
|
|
|
+ height: 350,
|
|
|
+ pagerConfig: {
|
|
|
+ currentPage: 1,
|
|
|
+ pageSize: 9999,
|
|
|
+ layouts: ['Total'],
|
|
|
+ },
|
|
|
+ rowConfig: {
|
|
|
+ isHover: true,
|
|
|
+ isCurrent: true,
|
|
|
+ keyField: 'productsid',
|
|
|
+ },
|
|
|
+ stripe: true,
|
|
|
+ radioConfig: {
|
|
|
+ reserve: true,
|
|
|
+ highlight: true,
|
|
|
+ checkMethod: ({ row }: any) =>
|
|
|
+ !linkedProductIds.value.includes(row.productsid),
|
|
|
+ },
|
|
|
+ proxyConfig: {
|
|
|
+ response: {
|
|
|
+ result: 'Data',
|
|
|
+ total: 'Total',
|
|
|
+ },
|
|
|
+ ajax: {
|
|
|
+ query: async () => {
|
|
|
+ const params: any = {
|
|
|
+ pageindex: 1,
|
|
|
+ rows: 9999,
|
|
|
+ 'productsname.like': searchKeyword.value || undefined,
|
|
|
+ };
|
|
|
+
|
|
|
+ const response = await getProductAndScqyListApi(params);
|
|
|
+
|
|
|
+ // 如果勾选了只显示未关联,则过滤掉已关联的产品
|
|
|
+ if (
|
|
|
+ showUnlinkedOnly.value &&
|
|
|
+ response?.Data &&
|
|
|
+ Array.isArray(response.Data)
|
|
|
+ ) {
|
|
|
+ // 获取最新的已关联产品列表
|
|
|
+ await fetchLinkedProducts();
|
|
|
+
|
|
|
+ // 过滤掉已关联的产品
|
|
|
+ response.Data = response.Data.filter(
|
|
|
+ (item: any) => !linkedProductIds.value.includes(item.productsid),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return response;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ columns: [
|
|
|
+ { type: 'radio', width: 60 },
|
|
|
+ {
|
|
|
+ title: '关联状态',
|
|
|
+ field: 'linkStatus',
|
|
|
+ width: 100,
|
|
|
+ slots: { default: 'linkStatus' },
|
|
|
+ },
|
|
|
+ { title: '产品名称', field: 'productsname' },
|
|
|
+ { title: '产品型号', field: 'productsmodel' },
|
|
|
+ { title: '机具类型', field: 'productsjjlx' },
|
|
|
+ { title: '品目', field: 'productspm' },
|
|
|
+ {
|
|
|
+ title: '生产企业',
|
|
|
+ field: 'scqyinfomc',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+};
|
|
|
+
|
|
|
+const addLinkGridEvents: VxeGridListeners<any> = {
|
|
|
+ radioChange: ({ row }) => {
|
|
|
+ selectedProduct.value = row;
|
|
|
+ // 设置当前行高亮
|
|
|
+ addLinkGridApi.grid.setCurrentRow(row);
|
|
|
+ },
|
|
|
+ cellClick: ({ row }) => {
|
|
|
+ // 只有未关联的产品才能选中
|
|
|
+ if (linkedProductIds.value.includes(row.productsid)) {
|
|
|
+ ElMessage.warning('该产品已存在关联关系');
|
|
|
+ } else {
|
|
|
+ // 点击行时设置radio选中状态
|
|
|
+ addLinkGridApi.grid.setRadioRow(row);
|
|
|
+ selectedProduct.value = row;
|
|
|
+ // 设置当前行高亮
|
|
|
+ addLinkGridApi.grid.setCurrentRow(row);
|
|
|
+ }
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+const [AddLinkGrid, addLinkGridApi] = useVbenVxeGrid({
|
|
|
+ gridEvents: addLinkGridEvents,
|
|
|
+ gridOptions: addLinkGridOptions,
|
|
|
+});
|
|
|
+
|
|
|
+// 获取已关联的产品列表
|
|
|
+const fetchLinkedProducts = async () => {
|
|
|
+ try {
|
|
|
+ const currentUserId = userStore.userInfo?.workeruserid || '';
|
|
|
+ if (!currentUserId) return [];
|
|
|
+
|
|
|
+ const response = await getProductAndScqyListApi({
|
|
|
+ pageindex: 1,
|
|
|
+ rows: 9999,
|
|
|
+ productsmerchantid: currentUserId,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (response && response.Data && Array.isArray(response.Data)) {
|
|
|
+ linkedProductIds.value = response.Data.map(
|
|
|
+ (item: any) => item.productsid,
|
|
|
+ );
|
|
|
+ return response.Data;
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取已关联产品列表失败', error);
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 搜索产品
|
|
|
+function handleSearch() {
|
|
|
+ addLinkGridApi.reload();
|
|
|
+}
|
|
|
+
|
|
|
+// 清除搜索
|
|
|
+function clearSearch() {
|
|
|
+ searchKeyword.value = '';
|
|
|
+ addLinkGridApi.reload();
|
|
|
+}
|
|
|
+
|
|
|
+// 切换关联状态过滤
|
|
|
+function handleToggleLinkedFilter() {
|
|
|
+ addLinkGridApi.reload();
|
|
|
+}
|
|
|
+
|
|
|
+// 重置新增关联表单
|
|
|
+function resetAddLinkForm() {
|
|
|
+ selectedProduct.value = null;
|
|
|
+ searchKeyword.value = '';
|
|
|
+ showUnlinkedOnly.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+/* 确认新增关联 */
|
|
|
+async function handleConfirmAddLink() {
|
|
|
+ if (!selectedProduct.value) {
|
|
|
+ ElMessage.warning('请选择要关联的产品');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ addLinkLoading.value = true;
|
|
|
+
|
|
|
+ // 调用API来建立关联关系
|
|
|
+ const currentUserId = userStore.userInfo?.workeruserid || '';
|
|
|
+ const currentRowIds = selectedProduct.value.productsmerchantid
|
|
|
+ ? selectedProduct.value.productsmerchantid.split(',')
|
|
|
+ : [];
|
|
|
+
|
|
|
+ // 判断当前用户是否已经关联了该产品
|
|
|
+ if (currentRowIds.includes(currentUserId)) {
|
|
|
+ ElMessage.warning('该产品已经关联了数据');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有关联,则在原有的基础上添加当前用户ID
|
|
|
+ const newIds = [...currentRowIds, currentUserId];
|
|
|
+ const newMerchantIds = newIds.join(',');
|
|
|
+
|
|
|
+ // 调用编辑产品API建立关联关系
|
|
|
+ await editProductApi({
|
|
|
+ 'productsid.value': selectedProduct.value.productsid,
|
|
|
+ productsmerchantid: newMerchantIds,
|
|
|
+ } as any);
|
|
|
+
|
|
|
+ ElMessage.success('新增关联成功');
|
|
|
+ emit('finish');
|
|
|
+ modalApi.close();
|
|
|
+ resetAddLinkForm();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('新增关联失败', error);
|
|
|
+ ElMessage.error('新增关联失败,请重试');
|
|
|
+ } finally {
|
|
|
+ addLinkLoading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const [Modal, modalApi] = useVbenModal({
|
|
|
+ title: '新增关联',
|
|
|
+ class: 'w-4/5',
|
|
|
+ closeOnClickModal: false,
|
|
|
+ closeOnPressEscape: false,
|
|
|
+ onCancel() {
|
|
|
+ resetAddLinkForm();
|
|
|
+ modalApi.close();
|
|
|
+ },
|
|
|
+ async onConfirm() {
|
|
|
+ await handleConfirmAddLink();
|
|
|
+ },
|
|
|
+ async onOpenChange(isOpen) {
|
|
|
+ if (isOpen) {
|
|
|
+ resetAddLinkForm();
|
|
|
+ // 获取已关联的产品列表
|
|
|
+ await fetchLinkedProducts();
|
|
|
+ }
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+// 暴露打开modal的方法
|
|
|
+const open = () => {
|
|
|
+ modalApi.open();
|
|
|
+};
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ open,
|
|
|
+});
|
|
|
+
|
|
|
+// 新增产品
|
|
|
+function handleAddProduct() {
|
|
|
+ if (formRef.value?.modalApi) {
|
|
|
+ formRef.value.modalApi.setData({
|
|
|
+ formType: 'create',
|
|
|
+ });
|
|
|
+ formRef.value.modalApi.open();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 新增产品完成后的回调
|
|
|
+function handleProductFinish() {
|
|
|
+ // 刷新产品列表
|
|
|
+ addLinkGridApi.reload();
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <Modal>
|
|
|
+ <div class="space-y-4">
|
|
|
+ <!-- 产品选择表格 -->
|
|
|
+ <div>
|
|
|
+ <div class="mb-3 flex items-center justify-between">
|
|
|
+ <div class="flex items-center space-x-3">
|
|
|
+ <h4 class="text-lg font-medium">选择产品</h4>
|
|
|
+ <el-button type="primary" size="small" @click="handleAddProduct">
|
|
|
+ 新增产品
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ <div class="flex items-center space-x-3">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="showUnlinkedOnly"
|
|
|
+ @change="handleToggleLinkedFilter"
|
|
|
+ >
|
|
|
+ 只显示未关联
|
|
|
+ </el-checkbox>
|
|
|
+ <div class="flex items-center space-x-2">
|
|
|
+ <el-input
|
|
|
+ v-model="searchKeyword"
|
|
|
+ placeholder="搜索产品名称"
|
|
|
+ clearable
|
|
|
+ class="w-60"
|
|
|
+ @input="handleSearch"
|
|
|
+ @clear="clearSearch"
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
+ >
|
|
|
+ <template #prefix>
|
|
|
+ <MdiMagnify class="text-gray-400" />
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ <el-button type="primary" @click="handleSearch"> 查询 </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <AddLinkGrid>
|
|
|
+ <template #linkStatus="{ row }">
|
|
|
+ <div class="flex items-center justify-center">
|
|
|
+ <el-tag
|
|
|
+ v-if="linkedProductIds.includes(row.productsid)"
|
|
|
+ type="warning"
|
|
|
+ size="small"
|
|
|
+ effect="light"
|
|
|
+ >
|
|
|
+ 已关联
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else type="success" size="small" effect="light">
|
|
|
+ 未关联
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </AddLinkGrid>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 选择信息显示 -->
|
|
|
+ <div v-if="selectedProduct" class="rounded bg-gray-50 p-3">
|
|
|
+ <h5 class="mb-2 text-sm font-medium">当前选择:</h5>
|
|
|
+ <div class="mb-1 text-sm text-gray-600">
|
|
|
+ 产品:{{ selectedProduct.productsname }} ({{
|
|
|
+ selectedProduct.productsmodel
|
|
|
+ }})
|
|
|
+ </div>
|
|
|
+ <div v-if="selectedProduct.scqyinfomc" class="text-sm text-gray-600">
|
|
|
+ 生产企业:{{ selectedProduct.scqyinfomc }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 新增产品表单 -->
|
|
|
+ <Form
|
|
|
+ ref="formRef"
|
|
|
+ :default-merchant-id="userStore.userInfo?.workeruserid"
|
|
|
+ @finish="handleProductFinish"
|
|
|
+ />
|
|
|
+ </Modal>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+/* 自定义选中行高亮颜色 */
|
|
|
+:deep(.vxe-table .vxe-body--row.row--current) {
|
|
|
+ background-color: #e6f3ff !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 自定义单选框选中行高亮颜色 */
|
|
|
+:deep(.vxe-table .vxe-body--row.row--radio-checked) {
|
|
|
+ background-color: #e6f3ff !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 鼠标悬停时的颜色 */
|
|
|
+:deep(.vxe-table .vxe-body--row:hover) {
|
|
|
+ background-color: #f0f8ff !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 已关联产品的样式 */
|
|
|
+:deep(.vxe-table .vxe-body--row.row--radio-disabled) {
|
|
|
+ color: #999 !important;
|
|
|
+ background-color: #f5f5f5 !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.vxe-table .vxe-body--row.row--radio-disabled .vxe-radio) {
|
|
|
+ cursor: not-allowed !important;
|
|
|
+}
|
|
|
+</style>
|