Browse Source

feature: 门店装修2

liudongzhi 2 months ago
parent
commit
a111258150

+ 29 - 0
src/assets/json/authMenuList.json

@@ -1015,6 +1015,35 @@
             "isAffix": false,
             "isKeepAlive": false
           }
+        },
+        {
+          "path": "/storeDecorationManagement/decorationCompany",
+          "name": "decorationCompany",
+          "component": "/storeDecoration/decorationCompany",
+          "meta": {
+            "icon": "OfficeBuilding",
+            "title": "装修公司",
+            "isLink": "",
+            "isHide": false,
+            "isFull": false,
+            "isAffix": false,
+            "isKeepAlive": false
+          }
+        },
+        {
+          "path": "/storeDecorationManagement/decorationCompanyDetail",
+          "name": "decorationCompanyDetail",
+          "component": "/storeDecoration/decorationCompanyDetail",
+          "meta": {
+            "icon": "Menu",
+            "title": "装修详情",
+            "activeMenu": "/storeDecorationManagement/decorationCompany",
+            "isLink": "",
+            "isHide": true,
+            "isFull": false,
+            "isAffix": false,
+            "isKeepAlive": false
+          }
         }
       ]
     },

+ 197 - 0
src/views/storeDecoration/decorationCompany.vue

@@ -0,0 +1,197 @@
+<template>
+  <div class="table-box button-table">
+    <ProTable ref="proTable" :columns="columns" :request-api="getTableList" :init-param="initParam" :data-callback="dataCallback">
+      <!-- 表格操作 -->
+      <template #operation="scope">
+        <el-button link type="primary" @click="handleContact(scope.row)">联系业主</el-button>
+        <el-button link type="primary" @click="handleView(scope.row)">查看详情</el-button>
+      </template>
+    </ProTable>
+  </div>
+</template>
+
+<script setup lang="tsx" name="decorationCompany">
+import { reactive, ref, onMounted, onActivated } from "vue";
+import { useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import ProTable from "@/components/ProTable/index.vue";
+import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
+import { getDecorationPage } from "@/api/modules/storeDecoration";
+import { localGet } from "@/utils";
+
+const router = useRouter();
+const proTable = ref<ProTableInstance>();
+
+// 装修类型枚举
+const decorationTypeEnum = [
+  { label: "新房装修", value: "1" },
+  { label: "旧房改造", value: "2" },
+  { label: "局部装修", value: "3" }
+];
+
+// 沟通状态枚举 (hasCommunicated: false:未沟通, true:已沟通)
+const communicationStatusEnum = [
+  { label: "未沟通", value: "false" },
+  { label: "已沟通", value: "true" }
+];
+
+// 初始化请求参数
+const initParam = reactive({});
+
+// 数据回调处理
+const dataCallback = (data: any) => {
+  if (data && data.data && data.data.records) {
+    return {
+      list: data.data.records || [],
+      total: data.data.total || 0
+    };
+  } else if (data && data.records) {
+    return {
+      list: data.records || [],
+      total: data.total || 0
+    };
+  }
+  return {
+    list: [],
+    total: 0
+  };
+};
+
+// 获取表格列表
+const getTableList = (params: any) => {
+  let newParams: any = {};
+  
+  // 只保留分页参数 page 和 size
+  if (params.pageNum) {
+    newParams.page = params.pageNum;
+  }
+  if (params.pageSize) {
+    newParams.size = params.pageSize;
+  }
+  
+  // 处理沟通状态参数 hasCommunicated(将字符串转换为布尔值)
+  // true:已沟通, false:未沟通
+  if (params.hasCommunicated !== undefined && params.hasCommunicated !== "" && params.hasCommunicated !== null) {
+    // 将字符串 "true"/"false" 转换为布尔值 true/false
+    if (params.hasCommunicated === "true" || params.hasCommunicated === true) {
+      newParams.hasCommunicated = true;
+    } else if (params.hasCommunicated === "false" || params.hasCommunicated === false) {
+      newParams.hasCommunicated = false;
+    }
+  }
+  
+  // 处理装修类型参数
+  if (params.renovationType !== undefined && params.renovationType !== "" && params.renovationType !== null) {
+    newParams.renovationType = params.renovationType;
+  }
+  
+  // 调用 /renovation/requirement/getPage 接口(只传 page、size 和筛选条件)
+  return getDecorationPage(newParams);
+};
+
+// 联系业主
+const handleContact = (row: any) => {
+  // TODO: 实现联系业主功能
+  ElMessage.info("联系业主功能待开发");
+};
+
+// 查看详情
+const handleView = (row: any) => {
+  router.push(`/storeDecorationManagement/decorationCompanyDetail?id=${row.id}`);
+};
+
+// 表格列配置
+const columns = reactive<ColumnProps<any>[]>([
+  { type: "index", fixed: "left", label: "序号", width: 80 },
+  {
+    prop: "requirementTitle",
+    label: "标题",
+    render: (scope: any) => {
+      return scope.row.requirementTitle || "--";
+    }
+  },
+  {
+    prop: "renovationType",
+    label: "装修类型",
+    render: (scope: any) => {
+      const type = decorationTypeEnum.find(item => item.value === String(scope.row.renovationType));
+      return type ? type.label : "--";
+    },
+    search: {
+      el: "select",
+      props: { placeholder: "请选择" }
+    },
+    enum: decorationTypeEnum,
+    fieldNames: { label: "label", value: "value" }
+  },
+  {
+    prop: "houseArea",
+    label: "面积(㎡)",
+    render: (scope: any) => {
+      return scope.row.houseArea || "--";
+    }
+  },
+  {
+    prop: "renovationBudget",
+    label: "装修预算(万元)",
+    render: (scope: any) => {
+      return scope.row.renovationBudget || "--";
+    }
+  },
+  {
+    prop: "city",
+    label: "所在城市",
+    render: (scope: any) => {
+      return scope.row.city || "--";
+    }
+  },
+  {
+    prop: "hasCommunicated",
+    label: "状态",
+    render: (scope: any) => {
+      const hasCommunicated = scope.row.hasCommunicated;
+      const statusMap: Record<string, { text: string; type: string }> = {
+        true: { text: "已沟通", type: "success" },
+        false: { text: "未沟通", type: "info" }
+      };
+      const statusKey = String(hasCommunicated);
+      const statusInfo = statusMap[statusKey] || { text: "--", type: "info" };
+      return (
+        <el-tag type={statusInfo.type as any} size="small">
+          {statusInfo.text}
+        </el-tag>
+      );
+    },
+    search: {
+      el: "select",
+      props: { placeholder: "请选择" }
+    },
+    enum: communicationStatusEnum,
+    fieldNames: { label: "label", value: "value" }
+  },
+  {
+    prop: "createdTime",
+    label: "发布时间",
+    render: (scope: any) => {
+      if (scope.row.createdTime) {
+        return scope.row.createdTime.replace(/-/g, "/");
+      }
+      return "--";
+    }
+  },
+  { prop: "operation", label: "操作", fixed: "right", width: 180 }
+]);
+
+// 页面加载时触发查询
+onMounted(() => {
+  proTable.value?.getTableList();
+});
+
+// 从其他页面返回时触发查询
+onActivated(() => {
+  proTable.value?.getTableList();
+});
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 294 - 0
src/views/storeDecoration/decorationCompanyDetail.vue

@@ -0,0 +1,294 @@
+<template>
+  <div class="detail-container">
+    <div class="card content-box">
+      <div class="detail-header">
+        <h3>详情</h3>
+        <el-button text @click="handleClose">
+          <el-icon><Close /></el-icon>
+        </el-button>
+      </div>
+      <el-form ref="formRef" :model="formData" label-width="140px" label-position="right">
+        <el-form-item label="用户昵称">
+          <el-input v-model="formData.userNickname" placeholder="请输入" disabled />
+        </el-form-item>
+
+        <el-form-item label="状态">
+          <el-tag :type="formData.hasCommunicated ? 'success' : 'info'" size="default">
+            {{ formData.hasCommunicated ? "已沟通" : "未沟通" }}
+          </el-tag>
+        </el-form-item>
+
+        <el-form-item label="发布时间">
+          <el-input v-model="formData.createdTime" placeholder="请输入" disabled />
+        </el-form-item>
+
+        <el-form-item label="装修类型">
+          <el-radio-group v-model="formData.renovationType" disabled>
+            <el-radio :label="1">新房装修</el-radio>
+            <el-radio :label="2">旧房改造</el-radio>
+            <el-radio :label="3">局部装修</el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item label="房屋面积(㎡)" required>
+          <el-input v-model="formData.houseArea" placeholder="请输入" disabled />
+        </el-form-item>
+
+        <el-form-item label="装修预算(万元)" required>
+          <el-input v-model="formData.renovationBudget" placeholder="请输入" disabled />
+        </el-form-item>
+
+        <el-form-item label="详细需求">
+          <el-input
+            v-model="formData.detailedRequirement"
+            type="textarea"
+            :rows="4"
+            placeholder="请输入"
+            disabled
+          />
+        </el-form-item>
+
+        <el-form-item label="期望装修时间" required>
+          <el-date-picker
+            v-model="formData.expectedRenovationTime"
+            type="date"
+            placeholder="请选择"
+            value-format="YYYY-MM-DD"
+            style="width: 100%"
+            disabled
+          />
+        </el-form-item>
+
+        <el-form-item label="上传房屋图纸" required>
+          <el-upload
+            v-model:file-list="fileList"
+            list-type="picture-card"
+            :disabled="true"
+            :on-preview="handlePictureCardPreview"
+            :on-remove="handleRemove"
+          >
+            <el-icon><Plus /></el-icon>
+          </el-upload>
+          <div class="upload-tip">({{ fileList.length }}/9)</div>
+        </el-form-item>
+
+        <el-form-item label="联系人" required>
+          <el-input v-model="formData.contactName" placeholder="请输入" disabled />
+        </el-form-item>
+
+        <el-form-item label="联系电话" required>
+          <el-input v-model="formData.contactPhone" placeholder="请输入" disabled />
+        </el-form-item>
+
+        <el-form-item label="所在城市" required>
+          <el-input v-model="formData.city" placeholder="请选择" disabled />
+        </el-form-item>
+
+        <el-form-item label="详细地址">
+          <el-input
+            v-model="formData.detailedAddress"
+            type="textarea"
+            :rows="3"
+            placeholder="请输入"
+            disabled
+          />
+        </el-form-item>
+      </el-form>
+
+      <div class="detail-footer">
+        <el-button @click="handleClose">返回</el-button>
+        <el-button type="primary" @click="handleContact">联系业主</el-button>
+      </div>
+    </div>
+
+    <!-- 图片预览 -->
+    <el-image-viewer
+      v-if="imageViewerVisible"
+      :url-list="imageViewerUrlList"
+      :initial-index="imageViewerInitialIndex"
+      @close="imageViewerVisible = false"
+    />
+  </div>
+</template>
+
+<script setup lang="ts" name="decorationCompanyDetail">
+import { ref, onMounted, watch } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import { Plus, Close } from "@element-plus/icons-vue";
+import type { UploadFile } from "element-plus";
+import { getDecorationDetail } from "@/api/modules/storeDecoration";
+
+const route = useRoute();
+const router = useRouter();
+
+const formRef = ref();
+const formData = ref<any>({
+  userNickname: "",
+  hasCommunicated: false,
+  createdTime: "",
+  requirementTitle: "",
+  renovationType: 1,
+  houseArea: "",
+  renovationBudget: "",
+  detailedRequirement: "",
+  expectedRenovationTime: "",
+  contactName: "",
+  contactPhone: "",
+  city: "",
+  detailedAddress: "",
+  attachmentUrls: []
+});
+
+const fileList = ref<UploadFile[]>([]);
+const imageViewerVisible = ref(false);
+const imageViewerUrlList = ref<string[]>([]);
+const imageViewerInitialIndex = ref(0);
+
+// 联系业主
+const handleContact = () => {
+  // TODO: 实现联系业主功能
+  ElMessage.info("联系业主功能待开发");
+};
+
+// 获取详情数据
+const initData = async () => {
+  const id = route.query.id;
+  if (!id) {
+    handleClose();
+    return;
+  }
+
+  try {
+    // 调用 /renovation/requirement/getDetail 接口
+    const res = await getDecorationDetail({ id: id as string });
+    if (res.code == 200 || res.code == 0) {
+      const data = res.data || res.data?.data || {};
+      formData.value = {
+        userNickname: data.storeName || data.userNickname || data.nickname || "",
+        hasCommunicated: data.hasCommunicated ?? false,
+        createdTime: data.createdTime || "",
+        requirementTitle: data.requirementTitle || "",
+        renovationType: data.renovationType || 1,
+        houseArea: data.houseArea || "",
+        renovationBudget: data.renovationBudget || "",
+        detailedRequirement: data.detailedRequirement || "",
+        expectedRenovationTime: data.expectedRenovationTime || "",
+        contactName: data.contactName || "",
+        contactPhone: data.contactPhone || "",
+        city: data.city || "",
+        detailedAddress: data.detailedAddress || "",
+        attachmentUrls: data.attachmentUrls || []
+      };
+
+      // 处理附件列表
+      if (formData.value.attachmentUrls && formData.value.attachmentUrls.length > 0) {
+        fileList.value = formData.value.attachmentUrls.map((url: string, index: number) => ({
+          uid: index,
+          name: `图片${index + 1}`,
+          url: url,
+          status: "success"
+        }));
+      }
+    }
+  } catch (error: any) {
+    console.error("获取详情失败:", error);
+    // 静默处理错误,不显示错误提示
+  }
+};
+
+// 图片预览
+const handlePictureCardPreview = (file: UploadFile) => {
+  if (file.url) {
+    imageViewerUrlList.value = fileList.value.map((item: UploadFile) => item.url || "").filter(Boolean);
+    imageViewerInitialIndex.value = fileList.value.findIndex((item: UploadFile) => item.uid === file.uid);
+    imageViewerVisible.value = true;
+  }
+};
+
+// 删除图片(详情页禁用,这里只是占位)
+const handleRemove = () => {
+  // 详情页不允许删除
+};
+
+// 关闭页面
+const handleClose = () => {
+  router.go(-1);
+};
+
+// 监听路由变化
+watch(
+  () => route.query.id,
+  () => {
+    if (route.query.id) {
+      initData();
+    }
+  },
+  { immediate: true }
+);
+
+onMounted(() => {
+  if (route.query.id) {
+    initData();
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.detail-container {
+  width: 100%;
+  min-height: 100%;
+  background-color: white;
+
+  .content-box {
+    padding: 20px;
+  }
+
+  .detail-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+    padding-bottom: 15px;
+    border-bottom: 1px solid #ebeef5;
+
+    h3 {
+      margin: 0;
+      font-size: 18px;
+      font-weight: 500;
+    }
+  }
+
+  :deep(.el-form-item) {
+    margin-bottom: 20px;
+  }
+
+  :deep(.el-radio-group) {
+    display: flex;
+    gap: 20px;
+  }
+
+  .upload-tip {
+    font-size: 12px;
+    color: #999;
+    margin-top: 5px;
+  }
+
+  .detail-footer {
+    text-align: center;
+    padding: 20px 0 0;
+    margin-top: 20px;
+    border-top: 1px solid #ebeef5;
+  }
+
+  :deep(.el-upload--picture-card) {
+    width: 100px;
+    height: 100px;
+  }
+
+  :deep(.el-upload-list--picture-card .el-upload-list__item) {
+    width: 100px;
+    height: 100px;
+  }
+}
+</style>