|
|
@@ -0,0 +1,693 @@
|
|
|
+<template>
|
|
|
+ <div class="p-2">
|
|
|
+ <!-- 返回按钮 + 标题 -->
|
|
|
+ <el-card shadow="never" class="mb-2">
|
|
|
+ <div class="flex items-center">
|
|
|
+ <el-button link @click="handleBack">
|
|
|
+ <el-icon><ArrowLeft /></el-icon>
|
|
|
+ 返回
|
|
|
+ </el-button>
|
|
|
+ <el-divider direction="vertical" />
|
|
|
+ <span class="text-base font-medium">样式设置</span>
|
|
|
+ <span v-if="siteName" class="text-gray-500 ml-2 text-sm">- {{ siteName }}</span>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 搜索 + 操作区域 -->
|
|
|
+ <el-card shadow="never" class="mb-2">
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
+ <span class="text-sm whitespace-nowrap">楼层名称</span>
|
|
|
+ <el-input
|
|
|
+ v-model="queryParams.name"
|
|
|
+ placeholder="请输入楼层名称"
|
|
|
+ clearable
|
|
|
+ style="width: 220px"
|
|
|
+ @keyup.enter="handleQuery"
|
|
|
+ />
|
|
|
+ <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
+ <el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
+ <el-button type="primary" icon="Plus" @click="handleAdd">添加楼层</el-button>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 表格区域 -->
|
|
|
+ <el-card shadow="never">
|
|
|
+ <template #header>
|
|
|
+ <div class="flex justify-between items-center">
|
|
|
+ <span class="font-bold text-[#409EFF]">楼层信息列表</span>
|
|
|
+ <el-tooltip content="刷新">
|
|
|
+ <el-button circle icon="Refresh" size="small" @click="getList" />
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <el-table v-loading="loading" border :data="floorList">
|
|
|
+ <el-table-column label="楼层名称" align="center" prop="name" min-width="150" />
|
|
|
+ <el-table-column label="是否显示" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-link
|
|
|
+ :type="scope.row.isShow === '1' ? 'primary' : 'info'"
|
|
|
+ :underline="false"
|
|
|
+ @click="handleToggleShow(scope.row)"
|
|
|
+ >
|
|
|
+ {{ scope.row.isShow === '1' ? '显示' : '隐藏' }}
|
|
|
+ </el-link>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="排序" align="center" prop="sort" width="80" />
|
|
|
+ <el-table-column label="更新时间" align="center" prop="updateTime" width="170" />
|
|
|
+ <el-table-column label="操作" align="center" width="300" fixed="right">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-link type="danger" :underline="false" class="mr-2" @click="handleDelete(scope.row)">删除</el-link>
|
|
|
+ <el-link type="primary" :underline="false" class="mr-2" @click="handleEdit(scope.row)">编辑</el-link>
|
|
|
+ <el-link type="primary" :underline="false" class="mr-2" @click="handleConfigProduct(scope.row)">配置商品</el-link>
|
|
|
+ <el-link type="warning" :underline="false" @click="handleConfigBrand(scope.row)">配置品牌</el-link>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="total > 0"
|
|
|
+ :total="total"
|
|
|
+ v-model:page="queryParams.pageNum"
|
|
|
+ v-model:limit="queryParams.pageSize"
|
|
|
+ @pagination="getList"
|
|
|
+ />
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 添加/编辑楼层 弹窗 -->
|
|
|
+ <el-dialog v-model="dialogVisible" :title="dialogTitle" width="620px" :close-on-click-modal="false">
|
|
|
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
|
|
+ <el-row :gutter="16">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="楼层名称" prop="name">
|
|
|
+ <el-input v-model="form.name" placeholder="请输入楼层名称" maxlength="50" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="链接" prop="link">
|
|
|
+ <el-input v-model="form.link" placeholder="请输入链接" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row :gutter="16">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="排序" prop="sort">
|
|
|
+ <el-input-number v-model="form.sort" :min="0" :max="9999" controls-position="right" style="width: 150px" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="是否显示" prop="isShow">
|
|
|
+ <el-switch v-model="form.isShow" active-value="1" inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-form-item label="图片" prop="imageUrl">
|
|
|
+ <image-upload v-model="form.imageUrl" :limit="1" :file-size="5" :file-type="['png', 'jpg', 'jpeg']" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button type="primary" :loading="submitLoading" @click="handleSubmit">确 认</el-button>
|
|
|
+ <el-button @click="dialogVisible = false">取 消</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 配置商品对话框 -->
|
|
|
+ <el-dialog v-model="productDialog.visible" title="推荐商品" width="900px" append-to-body>
|
|
|
+ <div class="flex items-center gap-3 mb-4">
|
|
|
+ <el-button @click="handleAddProduct">新增商品</el-button>
|
|
|
+ <el-button @click="handleImportProduct">导入商品</el-button>
|
|
|
+ </div>
|
|
|
+ <el-table v-loading="productDialog.loading" :data="linkedProducts" border>
|
|
|
+ <el-table-column label="商品编号" align="center" prop="productNo" width="140" />
|
|
|
+ <el-table-column label="商品图片" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-image v-if="scope.row.productImage" :src="scope.row.productImage" fit="cover" style="width: 60px; height: 60px" />
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="商品名称" align="center" prop="productName" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column label="价格" align="center" prop="price" width="120" />
|
|
|
+ <el-table-column label="操作" align="center" width="80">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-link type="danger" :underline="false" @click="handleRemoveLinkedProduct(scope.row)">删除</el-link>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="productDialog.visible = false">关 闭</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 配置品牌对话框 -->
|
|
|
+ <el-dialog v-model="brandDialog.visible" :title="`配置品牌 - ${brandDialog.floorName}`" width="900px" append-to-body>
|
|
|
+ <div class="flex items-center gap-3 mb-4">
|
|
|
+ <el-button type="primary" @click="handleAddBrand">新增品牌</el-button>
|
|
|
+ </div>
|
|
|
+ <el-table v-loading="brandDialog.loading" :data="linkedBrands" border>
|
|
|
+ <el-table-column label="品牌编号" align="center" prop="brandNo" width="120" />
|
|
|
+ <el-table-column label="品牌名称" align="center" prop="brandName" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column label="品牌图片" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-image v-if="scope.row.brandLogo" :src="scope.row.brandLogo" fit="contain" style="width: 60px; height: 40px" />
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" width="80">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-link type="danger" :underline="false" @click="handleRemoveLinkedBrand(scope.row)">删除</el-link>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <template #footer>
|
|
|
+ <el-button type="primary" @click="brandDialog.visible = false">关 闭</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 选择商品对话框 -->
|
|
|
+ <el-dialog v-model="selectProductDialog.visible" title="选择商品" width="900px" append-to-body>
|
|
|
+ <div class="flex items-center gap-3 mb-4">
|
|
|
+ <el-input v-model="selectProductDialog.productNo" placeholder="请输入商品编号" style="width: 200px" clearable />
|
|
|
+ <el-input v-model="selectProductDialog.productName" placeholder="请输入商品名称" style="width: 200px" clearable />
|
|
|
+ <el-button type="primary" @click="searchProducts">搜 索</el-button>
|
|
|
+ </div>
|
|
|
+ <el-table v-loading="selectProductDialog.loading" :data="productList" border @selection-change="handleProductSelectionChange">
|
|
|
+ <el-table-column type="selection" width="50" align="center" />
|
|
|
+ <el-table-column label="商品编号" align="center" prop="productNo" width="120" />
|
|
|
+ <el-table-column label="商品名称" align="center" prop="itemName" min-width="180" show-overflow-tooltip />
|
|
|
+ <el-table-column label="商品图片" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-image v-if="scope.row.productImage" :src="scope.row.productImage" fit="cover" style="width: 60px; height: 60px" />
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="价格" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ scope.row.minSellingPrice || scope.row.marketPrice || '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <pagination v-show="selectProductDialog.total > 0" v-model:page="selectProductDialog.pageNum" v-model:limit="selectProductDialog.pageSize" :total="selectProductDialog.total" @pagination="getProductList" />
|
|
|
+ <template #footer>
|
|
|
+ <el-button type="primary" @click="confirmSelectProducts">确 定</el-button>
|
|
|
+ <el-button @click="selectProductDialog.visible = false">取 消</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 选择品牌对话框 -->
|
|
|
+ <el-dialog v-model="selectBrandDialog.visible" title="选择品牌" width="900px" append-to-body>
|
|
|
+ <div class="flex items-center gap-3 mb-4">
|
|
|
+ <el-input v-model="selectBrandDialog.keyword" placeholder="请输入品牌编号或名称搜索" style="width: 300px" clearable />
|
|
|
+ <el-button type="primary" @click="searchBrands">搜 索</el-button>
|
|
|
+ </div>
|
|
|
+ <el-table v-loading="selectBrandDialog.loading" :data="brandList" border @selection-change="handleBrandSelectionChange">
|
|
|
+ <el-table-column type="selection" width="50" align="center" />
|
|
|
+ <el-table-column label="品牌编号" align="center" prop="brandNo" width="120" />
|
|
|
+ <el-table-column label="品牌名称" align="center" prop="brandName" min-width="180" show-overflow-tooltip />
|
|
|
+ <el-table-column label="品牌图片" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-image v-if="scope.row.brandLogo" :src="scope.row.brandLogo" fit="contain" style="width: 60px; height: 40px" />
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <pagination v-show="selectBrandDialog.total > 0" v-model:page="selectBrandDialog.pageNum" v-model:limit="selectBrandDialog.pageSize" :total="selectBrandDialog.total" @pagination="getBrandList" />
|
|
|
+ <template #footer>
|
|
|
+ <el-button type="primary" @click="confirmSelectBrands">确 定</el-button>
|
|
|
+ <el-button @click="selectBrandDialog.visible = false">取 消</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 导入商品对话框 -->
|
|
|
+ <el-dialog v-model="importProductDialog.visible" title="导入商品" width="500px" append-to-body>
|
|
|
+ <el-form label-width="90px">
|
|
|
+ <el-form-item label="商品编号">
|
|
|
+ <el-input v-model="importProductDialog.productNos" type="textarea" :rows="5" placeholder="请输入商品编号,多个用逗号隔开" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button type="primary" @click="confirmImportProducts">确 定</el-button>
|
|
|
+ <el-button @click="importProductDialog.visible = false">取 消</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="StyleDesign" lang="ts">
|
|
|
+import { listSiteFloor, getSiteFloor, addSiteFloor, updateSiteFloor, delSiteFloor } from '@/api/product/siteFloor';
|
|
|
+import { SiteFloorVO, SiteFloorForm, SiteFloorQuery } from '@/api/product/siteFloor/types';
|
|
|
+import { listSiteFloorLink, addSiteFloorLink, delSiteFloorLink } from '@/api/product/siteFloorLink';
|
|
|
+import { listProduct } from '@/api/product/base';
|
|
|
+import { listBrand } from '@/api/product/brand';
|
|
|
+import { useRouter, useRoute } from 'vue-router';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
+const router = useRouter();
|
|
|
+const route = useRoute();
|
|
|
+
|
|
|
+// 路由参数
|
|
|
+const siteId = computed(() => route.query.siteId as string | undefined);
|
|
|
+const siteName = computed(() => route.query.siteName as string | undefined);
|
|
|
+
|
|
|
+const floorList = ref<SiteFloorVO[]>([]);
|
|
|
+const loading = ref(false);
|
|
|
+const total = ref(0);
|
|
|
+const dialogVisible = ref(false);
|
|
|
+const dialogTitle = ref('添加楼层');
|
|
|
+const submitLoading = ref(false);
|
|
|
+
|
|
|
+const queryParams = ref<SiteFloorQuery>({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ name: undefined,
|
|
|
+ siteId: siteId.value
|
|
|
+});
|
|
|
+
|
|
|
+const formRef = ref<ElFormInstance>();
|
|
|
+const form = ref<SiteFloorForm>({
|
|
|
+ name: undefined,
|
|
|
+ link: undefined,
|
|
|
+ imageUrl: undefined,
|
|
|
+ isShow: '1',
|
|
|
+ sort: 0,
|
|
|
+ siteId: siteId.value
|
|
|
+});
|
|
|
+
|
|
|
+const rules = {
|
|
|
+ name: [{ required: true, message: '请输入楼层名称', trigger: 'blur' }],
|
|
|
+ isShow: [{ required: true, message: '请选择是否显示', trigger: 'change' }]
|
|
|
+};
|
|
|
+
|
|
|
+// 配置商品弹框
|
|
|
+const productDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ loading: false,
|
|
|
+ floorId: null as string | number | null,
|
|
|
+ floorName: ''
|
|
|
+});
|
|
|
+const linkedProducts = ref<any[]>([]);
|
|
|
+
|
|
|
+// 配置品牌弹框
|
|
|
+const brandDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ loading: false,
|
|
|
+ floorId: null as string | number | null,
|
|
|
+ floorName: ''
|
|
|
+});
|
|
|
+const linkedBrands = ref<any[]>([]);
|
|
|
+
|
|
|
+// 选择商品弹框
|
|
|
+const selectProductDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ loading: false,
|
|
|
+ productNo: '',
|
|
|
+ productName: '',
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0
|
|
|
+});
|
|
|
+const productList = ref<any[]>([]);
|
|
|
+const selectedProducts = ref<any[]>([]);
|
|
|
+
|
|
|
+// 选择品牌弹框
|
|
|
+const selectBrandDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ loading: false,
|
|
|
+ keyword: '',
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0
|
|
|
+});
|
|
|
+const brandList = ref<any[]>([]);
|
|
|
+const selectedBrands = ref<any[]>([]);
|
|
|
+
|
|
|
+// 导入商品弹框
|
|
|
+const importProductDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ productNos: ''
|
|
|
+});
|
|
|
+
|
|
|
+/** 获取楼层列表 */
|
|
|
+const getList = async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const res = await listSiteFloor({ ...queryParams.value, siteId: siteId.value });
|
|
|
+ floorList.value = res.rows;
|
|
|
+ total.value = res.total;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取楼层列表失败:', error);
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索 */
|
|
|
+const handleQuery = () => {
|
|
|
+ queryParams.value.pageNum = 1;
|
|
|
+ getList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 重置 */
|
|
|
+const resetQuery = () => {
|
|
|
+ queryParams.value = {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ name: undefined,
|
|
|
+ siteId: siteId.value
|
|
|
+ };
|
|
|
+ getList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 返回 */
|
|
|
+const handleBack = () => {
|
|
|
+ router.push('/customerOperation/vipSite');
|
|
|
+};
|
|
|
+
|
|
|
+/** 添加楼层 */
|
|
|
+const handleAdd = () => {
|
|
|
+ form.value = { name: undefined, link: undefined, imageUrl: undefined, isShow: '1', sort: 0, siteId: siteId.value };
|
|
|
+ dialogTitle.value = '添加楼层';
|
|
|
+ dialogVisible.value = true;
|
|
|
+ nextTick(() => formRef.value?.clearValidate());
|
|
|
+};
|
|
|
+
|
|
|
+/** 编辑楼层 */
|
|
|
+const handleEdit = async (row: SiteFloorVO) => {
|
|
|
+ try {
|
|
|
+ const res = await getSiteFloor(row.id);
|
|
|
+ console.log('res.data', res.data);
|
|
|
+ form.value = { ...res.data };
|
|
|
+ dialogTitle.value = '编辑楼层';
|
|
|
+ dialogVisible.value = true;
|
|
|
+ nextTick(() => formRef.value?.clearValidate());
|
|
|
+ } catch (error) {
|
|
|
+ proxy?.$modal.msgError('获取楼层信息失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 切换显示状态 */
|
|
|
+const handleToggleShow = async (row: SiteFloorVO) => {
|
|
|
+ const newIsShow = row.isShow === '1' ? '0' : '1';
|
|
|
+ const text = newIsShow === '1' ? '显示' : '隐藏';
|
|
|
+ try {
|
|
|
+ await proxy?.$modal.confirm(`确认要将楼层"${row.name}"设置为"${text}"吗?`);
|
|
|
+ await updateSiteFloor({ id: row.id, isShow: newIsShow, siteId: row.siteId });
|
|
|
+ proxy?.$modal.msgSuccess('操作成功');
|
|
|
+ getList();
|
|
|
+ } catch {}
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除楼层 */
|
|
|
+const handleDelete = async (row: SiteFloorVO) => {
|
|
|
+ try {
|
|
|
+ await proxy?.$modal.confirm(`确认要删除楼层"${row.name}"吗?`);
|
|
|
+ await delSiteFloor(row.id);
|
|
|
+ proxy?.$modal.msgSuccess('删除成功');
|
|
|
+ getList();
|
|
|
+ } catch {}
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交表单 */
|
|
|
+const handleSubmit = async () => {
|
|
|
+ await formRef.value?.validate();
|
|
|
+ submitLoading.value = true;
|
|
|
+ try {
|
|
|
+ if (form.value.id) {
|
|
|
+ await updateSiteFloor(form.value as SiteFloorForm);
|
|
|
+ proxy?.$modal.msgSuccess('修改成功');
|
|
|
+ } else {
|
|
|
+ await addSiteFloor(form.value as SiteFloorForm);
|
|
|
+ proxy?.$modal.msgSuccess('添加成功');
|
|
|
+ }
|
|
|
+ dialogVisible.value = false;
|
|
|
+ getList();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('提交失败:', error);
|
|
|
+ } finally {
|
|
|
+ submitLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 配置商品 */
|
|
|
+const handleConfigProduct = (row: SiteFloorVO) => {
|
|
|
+ productDialog.floorId = row.id;
|
|
|
+ productDialog.floorName = row.name;
|
|
|
+ productDialog.visible = true;
|
|
|
+ getLinkedProducts();
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取已关联商品 */
|
|
|
+const getLinkedProducts = async () => {
|
|
|
+ if (!productDialog.floorId) return;
|
|
|
+ productDialog.loading = true;
|
|
|
+ try {
|
|
|
+ const res = await listSiteFloorLink({ floorId: productDialog.floorId, type: 1, pageNum: 1, pageSize: 1000 });
|
|
|
+ const links = res.rows || [];
|
|
|
+ if (links.length === 0) {
|
|
|
+ linkedProducts.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const productIds = links.map((item: any) => item.productId).filter(Boolean);
|
|
|
+ if (productIds.length > 0) {
|
|
|
+ const productRes = await listProduct({ ids: productIds.join(','), pageSize: 1000 });
|
|
|
+ const productMap = new Map<string, any>((productRes.rows || []).map((p: any) => [String(p.id), p]));
|
|
|
+ linkedProducts.value = links.map((item: any) => {
|
|
|
+ const p = productMap.get(String(item.productId)) || {};
|
|
|
+ return { ...item, productName: p.itemName || item.productName || '', productImage: p.productImage || item.productImage || '', price: p.minSellingPrice || p.marketPrice || '' };
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ linkedProducts.value = links;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载关联商品失败', error);
|
|
|
+ } finally {
|
|
|
+ productDialog.loading = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除关联商品 */
|
|
|
+const handleRemoveLinkedProduct = (row: any) => {
|
|
|
+ proxy?.$modal.confirm('是否确认删除该商品?').then(() => {
|
|
|
+ delSiteFloorLink(row.id).then(() => {
|
|
|
+ proxy?.$modal.msgSuccess('删除成功');
|
|
|
+ getLinkedProducts();
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增商品 */
|
|
|
+const handleAddProduct = () => {
|
|
|
+ selectProductDialog.productNo = '';
|
|
|
+ selectProductDialog.productName = '';
|
|
|
+ selectProductDialog.pageNum = 1;
|
|
|
+ selectProductDialog.visible = true;
|
|
|
+ getProductList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 导入商品 */
|
|
|
+const handleImportProduct = () => {
|
|
|
+ importProductDialog.productNos = '';
|
|
|
+ importProductDialog.visible = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 确认导入商品 */
|
|
|
+const confirmImportProducts = async () => {
|
|
|
+ const input = importProductDialog.productNos.trim();
|
|
|
+ if (!input) {
|
|
|
+ proxy?.$modal.msgWarning('请输入商品编号');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const productNos = input.split(/[,,\s\n]+/).map((s: string) => s.trim()).filter(Boolean);
|
|
|
+ if (productNos.length === 0) {
|
|
|
+ proxy?.$modal.msgWarning('请输入有效的商品编号');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const existingProductNos = linkedProducts.value.map((item: any) => item.productNo);
|
|
|
+ const newProductNos = productNos.filter((no: string) => !existingProductNos.includes(no));
|
|
|
+ if (newProductNos.length === 0) {
|
|
|
+ proxy?.$modal.msgWarning('所有商品编号已存在,请勿重复添加');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const productRes = await listProduct({ productNos: newProductNos.join(','), pageSize: 1000 });
|
|
|
+ const productMap = new Map<string, any>((productRes.rows || []).map((p: any) => [p.productNo, p]));
|
|
|
+ for (const productNo of newProductNos) {
|
|
|
+ const product = productMap.get(productNo);
|
|
|
+ if (!product) {
|
|
|
+ console.warn(`商品编号 ${productNo} 不存在`);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ await addSiteFloorLink({ floorId: productDialog.floorId, type: 1, productId: product.id, productNo, sort: 0, status: '0' });
|
|
|
+ }
|
|
|
+ const skipped = productNos.length - newProductNos.length;
|
|
|
+ proxy?.$modal.msgSuccess(skipped > 0 ? `导入成功,${skipped}个商品已存在被跳过` : '导入成功');
|
|
|
+ importProductDialog.visible = false;
|
|
|
+ getLinkedProducts();
|
|
|
+ } catch (error) {
|
|
|
+ proxy?.$modal.msgError('导入失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取商品列表 */
|
|
|
+const getProductList = async () => {
|
|
|
+ selectProductDialog.loading = true;
|
|
|
+ try {
|
|
|
+ const res = await listProduct({
|
|
|
+ productNo: selectProductDialog.productNo,
|
|
|
+ keyword: selectProductDialog.productName,
|
|
|
+ pageNum: selectProductDialog.pageNum,
|
|
|
+ pageSize: selectProductDialog.pageSize
|
|
|
+ });
|
|
|
+ productList.value = res.rows || [];
|
|
|
+ selectProductDialog.total = res.total || 0;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载商品列表失败', error);
|
|
|
+ } finally {
|
|
|
+ selectProductDialog.loading = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索商品 */
|
|
|
+const searchProducts = () => {
|
|
|
+ selectProductDialog.pageNum = 1;
|
|
|
+ getProductList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 商品选择变化 */
|
|
|
+const handleProductSelectionChange = (selection: any[]) => {
|
|
|
+ selectedProducts.value = selection;
|
|
|
+};
|
|
|
+
|
|
|
+/** 确认选择商品 */
|
|
|
+const confirmSelectProducts = async () => {
|
|
|
+ if (selectedProducts.value.length === 0) {
|
|
|
+ proxy?.$modal.msgWarning('请选择商品');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const existingProductNos = linkedProducts.value.map((item: any) => item.productNo);
|
|
|
+ const duplicates = selectedProducts.value.filter((p: any) => existingProductNos.includes(p.productNo));
|
|
|
+ if (duplicates.length > 0) {
|
|
|
+ const names = duplicates.map((p: any) => p.itemName || p.productNo).join('、');
|
|
|
+ proxy?.$modal.msgWarning(`商品 ${names} 已存在,请勿重复添加`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ for (const product of selectedProducts.value) {
|
|
|
+ await addSiteFloorLink({ floorId: productDialog.floorId, type: 1, productId: product.id, productNo: product.productNo, sort: 0, status: '0' });
|
|
|
+ }
|
|
|
+ proxy?.$modal.msgSuccess('添加成功');
|
|
|
+ selectProductDialog.visible = false;
|
|
|
+ getLinkedProducts();
|
|
|
+ } catch (error) {
|
|
|
+ proxy?.$modal.msgError('添加失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 配置品牌 */
|
|
|
+const handleConfigBrand = (row: SiteFloorVO) => {
|
|
|
+ brandDialog.floorId = row.id;
|
|
|
+ brandDialog.floorName = row.name;
|
|
|
+ brandDialog.visible = true;
|
|
|
+ getLinkedBrands();
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取已关联品牌 */
|
|
|
+const getLinkedBrands = async () => {
|
|
|
+ if (!brandDialog.floorId) return;
|
|
|
+ brandDialog.loading = true;
|
|
|
+ try {
|
|
|
+ const res = await listSiteFloorLink({ floorId: brandDialog.floorId, type: 2, pageNum: 1, pageSize: 1000 });
|
|
|
+ const links = res.rows || [];
|
|
|
+ if (links.length === 0) {
|
|
|
+ linkedBrands.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const brandIds = links.map((item: any) => item.brandId).filter(Boolean);
|
|
|
+ const brandMap = new Map<string, any>();
|
|
|
+ if (brandIds.length > 0) {
|
|
|
+ const brandRes = await listBrand({ ids: brandIds.join(','), pageSize: 200 });
|
|
|
+ (brandRes.rows || []).forEach((b: any) => brandMap.set(String(b.id), b));
|
|
|
+ }
|
|
|
+ linkedBrands.value = links.map((item: any) => {
|
|
|
+ const brand = brandMap.get(String(item.brandId)) || {};
|
|
|
+ return { ...item, brandName: brand.brandName || item.brandName || '', brandLogo: brand.brandLogo || item.brandLogo || '' };
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载关联品牌失败', error);
|
|
|
+ } finally {
|
|
|
+ brandDialog.loading = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除关联品牌 */
|
|
|
+const handleRemoveLinkedBrand = (row: any) => {
|
|
|
+ proxy?.$modal.confirm('是否确认删除该品牌?').then(() => {
|
|
|
+ delSiteFloorLink(row.id).then(() => {
|
|
|
+ proxy?.$modal.msgSuccess('删除成功');
|
|
|
+ getLinkedBrands();
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增品牌 */
|
|
|
+const handleAddBrand = () => {
|
|
|
+ selectBrandDialog.keyword = '';
|
|
|
+ selectBrandDialog.pageNum = 1;
|
|
|
+ selectBrandDialog.visible = true;
|
|
|
+ getBrandList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取品牌列表 */
|
|
|
+const getBrandList = async () => {
|
|
|
+ selectBrandDialog.loading = true;
|
|
|
+ try {
|
|
|
+ const res = await listBrand({ keyword: selectBrandDialog.keyword, pageNum: selectBrandDialog.pageNum, pageSize: selectBrandDialog.pageSize });
|
|
|
+ brandList.value = res.rows || [];
|
|
|
+ selectBrandDialog.total = res.total || 0;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载品牌列表失败', error);
|
|
|
+ } finally {
|
|
|
+ selectBrandDialog.loading = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索品牌 */
|
|
|
+const searchBrands = () => {
|
|
|
+ selectBrandDialog.pageNum = 1;
|
|
|
+ getBrandList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 品牌选择变化 */
|
|
|
+const handleBrandSelectionChange = (selection: any[]) => {
|
|
|
+ selectedBrands.value = selection;
|
|
|
+};
|
|
|
+
|
|
|
+/** 确认选择品牌 */
|
|
|
+const confirmSelectBrands = async () => {
|
|
|
+ if (selectedBrands.value.length === 0) {
|
|
|
+ proxy?.$modal.msgWarning('请选择品牌');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const existingBrandNos = linkedBrands.value.map((item: any) => item.brandNo);
|
|
|
+ const duplicates = selectedBrands.value.filter((b: any) => existingBrandNos.includes(b.brandNo));
|
|
|
+ if (duplicates.length > 0) {
|
|
|
+ const names = duplicates.map((b: any) => b.brandName || b.brandNo).join('、');
|
|
|
+ proxy?.$modal.msgWarning(`品牌 ${names} 已存在,请勿重复添加`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ for (const brand of selectedBrands.value) {
|
|
|
+ await addSiteFloorLink({ floorId: brandDialog.floorId, type: 2, brandId: brand.id, brandNo: brand.brandNo, sort: 0, status: '0' });
|
|
|
+ }
|
|
|
+ proxy?.$modal.msgSuccess('添加成功');
|
|
|
+ selectBrandDialog.visible = false;
|
|
|
+ getLinkedBrands();
|
|
|
+ } catch (error) {
|
|
|
+ proxy?.$modal.msgError('添加失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getList();
|
|
|
+});
|
|
|
+</script>
|