Explorar o código

✨ 修改公司信息页面并添加编辑功能

- 重构了公司信息页面的布局和样式
- 添加了公司编辑功能,包括编辑抽屉组件
- 实现了公司概览数据的获取和展示
- 优化了联系方式的展示和编辑
- 统一了平台和店铺信息页面的样式
- 新增了公司信息表格列的定义
WanGxC hai 8 meses
pai
achega
9217a69dd5

+ 8 - 39
src/views/company-information/api.ts

@@ -13,56 +13,25 @@ export function getCardData(query: any) {
 
 export function getTableData(query: any) {
   return request({
-    url: apiPrefix,
+    url: apiPrefix + 'shop/',
     method: 'GET',
     params: query,
   });
 }
 
-export function getPlatformDetailOverview(query: any) {
+export function getCompanyOverview(query: any) {
   return request({
-    url: apiPrefix + 'platform/',
+    url: apiPrefix + `${query.companyId}/`,
     method: 'GET',
-    params: query,
-  });
-}
-
-export function getShopDetailOverview(query: any) {
-  return request({
-    url: apiPrefix + 'detail/',
-    method: 'GET',
-    params: query,
   });
 }
 
-export function getCurrentInfo(query: any) {
+export function updateShopDetail(query: any) {
   return request({
-    url: apiPrefix + 'current/',
-    method: 'GET',
-    params: query,
-  });
-}
-
-export function getHistoryInfo(query: any) {
-  return request({
-    url: apiPrefix + 'past/',
-    method: 'GET',
-    params: query,
-  });
-}
-
-export function getComputerInfo(query: any) {
-  return request({
-    url: apiPrefix + 'computer/',
-    method: 'GET',
-    params: query,
-  });
-}
-
-export function getShopSelect() {
-  return request({
-    url: apiPrefix + 'box/',
-    method: 'GET',
+    url: apiPrefix + `${query.id}/`,
+    method: 'POST',
+    params: { partial: query.partial },
+    data: query.formData,
   });
 }
 

+ 0 - 1
src/views/company-information/components/CompanyCreate.vue

@@ -146,7 +146,6 @@ const resetForm = (formEl: FormInstance | undefined) => {
         <div class="flex gap-2.5 items-start">
           <el-form-item
               :prop="'contacts.' + index + '.phone'"
-              :rules="rules.contacts.phone"
           >
             <el-input
                 v-model="contact.phone"

+ 103 - 20
src/views/company-information/components/CompanyDetail.vue

@@ -5,17 +5,19 @@
  * @Author: Cheney
  */
 
-import { Link, Picture as IconPicture } from '@element-plus/icons-vue';
-import { platformColumns } from '/@/views/shop-information/useColumns';
+import { Edit, Link, Picture as IconPicture } from '@element-plus/icons-vue';
+import { companyColumns } from '../useColumns';
 import { usePagination } from '/@/utils/usePagination';
 import { useTableData } from '/@/utils/useTableData';
-import * as api from '/@/views/shop-information/api';
+import * as api from '../api';
 import router from '/@/router';
+import { useResponse } from '/@/utils/useResponse';
+import EditDrawer from '../components/EditDrawer.vue';
 
 
 const route = useRoute();
-const companyId = route.query.platform;
-const platformOverview: any = ref([]);
+const companyId = route.query.id;
+const companyOverview: any = ref([]);
 const overviewLoading = ref();
 const { tableOptions, handlePageChange } = usePagination(fetchCompanyDetail);
 const platformTableData = ref([]);
@@ -44,67 +46,139 @@ const gridOptions: any = reactive({
     icon: 'vxe-icon-indicator roll',
     text: '正在拼命加载中...'
   },
-  columns: platformColumns,
+  columns: companyColumns,
   data: platformTableData
 });
 
+const isOpen = ref(false);
+
+onBeforeMount(() => {
+  fetchCompanyOverview();
+  fetchCompanyDetail();
+});
+
 async function fetchCompanyDetail() {
   const query = {
-    companyId,
+    id: companyId,
     page: gridOptions.pagerConfig.page,
     limit: gridOptions.pagerConfig.limit
   };
   await useTableData(api.getTableData, query, gridOptions);
 }
 
+async function fetchCompanyOverview() {
+  const res = await useResponse({ companyId }, api.getCompanyOverview, overviewLoading);
+  companyOverview.value = res.data;
+}
+
 function handleNavigate(item: any) {
   router.push({
     path: '/shop/detail',
     query: { platformNumber: item.platformNumber }
   });
 }
+
+function drawerOpen() {
+  isOpen.value = true;
+}
+
+function handleRefresh() {
+  fetchCompanyOverview();
+}
+
+const contactGroups = computed(() => {
+  const contacts = companyOverview.value?.companyPhoneEmail || [];
+  if (!Array.isArray(contacts)) {
+    console.error('companyPhoneEmail is not an array:', contacts);
+    return [];
+  }
+
+  const groups = [];
+
+  if (contacts.length > 0) {
+    groups.push(contacts.slice(0, 2));
+  }
+
+  for (let i = 2; i < contacts.length; i += 3) {
+    groups.push(contacts.slice(i, i + 3));
+  }
+
+  return groups;
+});
 </script>
 
 <template>
   <div class="p-2.5">
-    <el-card v-loading="overviewLoading" body-class="flex items-center" shadow="hover" style="border: none">
+    <el-card v-loading="overviewLoading" body-class="flex items-center gap-10" shadow="hover" style="border: none">
       <el-image :src="`/src/assets/platformImg/${ companyId }.png`" class="mr-7 rounded-2xl" fit="contain"
                 style="height: 120px; width: 120px;">
         <template #error>
           <div class="mr-3.5 flex items-center justify-center text-5xl"
-               style="height: 130px; width: 130px; background-color: #f5f5f5">
+               style="height: 100%; width: 100%; background-color: #f5f5f5">
             <el-icon>
               <icon-picture/>
             </el-icon>
           </div>
         </template>
       </el-image>
-      <div class="text-lg">
-        <div class="font-semibold">
-          公司编号/名称:
-          <span class="font-medium italic ml-1.5" style="color: #64748b"> 
-            {{ platformOverview[0]?.platform ? platformOverview[0]?.platform : '--' }} 
+      <div class="text-lg whitespace-nowrap">
+        <div class="font-semibold relative">
+          <el-button :icon="Edit" class="absolute" link style="left: -20px; bottom: 2px;" type="warning"
+                     @click="drawerOpen"></el-button>
+          公司名称:
+          <span class="font-medium italic ml-1.5" style="color: #64748b;"> 
+            {{ companyOverview?.company ? companyOverview?.company : '--' }} 
           </span>
         </div>
         <div class="font-semibold">
-          公司:
+          公司英文名:
           <span class="font-medium italic ml-1.5" style="color: #64748b">
-            {{ platformOverview[0]?.countCompany ? platformOverview[0]?.countCompany : '--' }} 
+            {{ companyOverview?.companyEnglishName ? companyOverview?.companyEnglishName : '--' }} 
           </span>
         </div>
         <div class="font-semibold">
-          平台:
+          公司地址:
           <span class="font-medium italic ml-1.5" style="color: #64748b">
-            {{ platformOverview[0]?.countShop ? platformOverview[0]?.countShop : '--' }}
+            {{ companyOverview?.address ? companyOverview?.address : '--' }}
+          </span>
+        </div>
+      </div>
+      <div class="text-lg whitespace-nowrap">
+        <div class="font-semibold">
+          公司法人:
+          <span class="font-medium italic ml-1.5" style="color: #64748b"> 
+            {{ companyOverview?.juridicalPerson ? companyOverview?.juridicalPerson : '--' }} 
           </span>
         </div>
         <div class="font-semibold">
-          电脑:
+          VAT税号:
           <span class="font-medium italic ml-1.5" style="color: #64748b"> 
-            {{ platformOverview[0]?.countComputer ? platformOverview[0]?.countComputer : '--' }}
+            {{ companyOverview?.vatNumber ? companyOverview?.vatNumber : '--' }} 
+          </span>
+        </div>
+        <div class="font-semibold">
+          VAT税号公司:
+          <span class="font-medium italic ml-1.5" style="color: #64748b"> 
+            {{ companyOverview?.vatCompany ? companyOverview?.vatCompany : '--' }} 
           </span>
         </div>
       </div>
+      <div v-if="contactGroups.length > 0" class="flex flex-wrap whitespace-nowrap">
+        <div v-for="(group, groupIndex) in contactGroups" :key="groupIndex">
+          <div class="text-lg font-semibold">
+            <template v-if="groupIndex === 0">
+              公司联系方式:
+            </template>
+            <div v-for="(item, itemIndex) in group" :key="itemIndex"
+                 class="font-medium italic mr-3" style="color: #64748b">
+              {{ item.phone }} - {{ item.email }}
+            </div>
+          </div>
+        </div>
+      </div>
+      <div v-else class="text-lg font-semibold">
+        暂无联系方式
+      </div>
     </el-card>
 
     <el-card body-style="padding-top: 10px" class="mt-2.5" shadow="hover" style="border: none">
@@ -128,6 +202,15 @@ function handleNavigate(item: any) {
         </template>
       </vxe-grid>
     </el-card>
+
+    <EditDrawer
+        v-if="isOpen"
+        v-model="isOpen"
+        :company="companyOverview.company"
+        :companyOverview
+        :formSelect
+        @refresh="handleRefresh"
+    />
   </div>
 </template>
 

+ 213 - 0
src/views/company-information/components/EditDrawer.vue

@@ -0,0 +1,213 @@
+<script lang="ts" setup>
+/**
+ * @Name: EditDrawer.vue
+ * @Description: 公司编辑
+ * @Author: Cheney
+ */
+
+import { ElMessage, FormInstance, FormRules } from 'element-plus';
+import { useResponse } from '/@/utils/useResponse';
+import * as api from '../api';
+import { Delete, Plus } from '@element-plus/icons-vue';
+import { cloneDeep } from 'lodash';
+
+
+const loading = ref(false);
+const isOpen = defineModel({ default: false });
+const { companyOverview, company } = defineProps<{
+  companyOverview: any;
+  company: any;
+}>();
+
+const emit = defineEmits([ 'refresh' ]);
+
+onBeforeMount(() => {
+  replaceCol();
+});
+
+interface ContactItem {
+  phone: string;
+  email: string;
+}
+
+interface RuleForm {
+  company: string;
+  companyEnglishName: string;
+  address: string;
+  juridicalPerson: string;
+  vatNumber: string;
+  vatCompany: string;
+  contacts: ContactItem[];
+}
+
+const ruleFormRef = ref<FormInstance>();
+const ruleForm = reactive<RuleForm>({
+  company: '',
+  companyEnglishName: '',
+  address: '',
+  juridicalPerson: '',
+  vatNumber: '',
+  vatCompany: '',
+  contacts: [
+    {
+      phone: '',
+      email: ''
+    }
+  ]
+});
+
+const rules = reactive<FormRules<RuleForm>>({
+  company: [
+    { required: true, message: 'Please input platform name', trigger: 'blur' }
+  ],
+  companyEnglishName: [
+    { required: true, message: 'Please input platform name', trigger: 'blur' }
+  ],
+  address: [
+    { required: true, message: 'Please input country name', trigger: 'blur' }
+  ],
+  juridicalPerson: [
+    { required: true, message: 'Please input platform name', trigger: 'blur' }
+  ],
+  vatNumber: [
+    { required: true, message: 'Please select line', trigger: 'change' }
+  ],
+  vatCompany: [
+    { required: true, message: 'Please select line', trigger: 'change' }
+  ],
+  contacts: {
+    phone: [ { required: true, message: '请输入电话号码', trigger: 'blur' } ],
+    email: [
+      { required: true, message: '请输入邮箱地址', trigger: 'blur' },
+      { type: 'email', message: '请输入有效的邮箱地址', trigger: 'blur' }
+    ]
+  }
+});
+
+const addContact = () => {
+  ruleForm.contacts.push({
+    phone: '',
+    email: ''
+  });
+};
+
+const removeContact = (item: ContactItem) => {
+  const index = ruleForm.contacts.indexOf(item);
+  if (index !== -1) {
+    ruleForm.contacts.splice(index, 1);
+  }
+};
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      const formData = {
+        ...ruleForm,
+        companyPhoneEmail: ruleForm.contacts.map(contact => ({
+          email: contact.email,
+          phone: contact.phone
+        }))
+      };
+      await useResponse({ id: companyOverview.id, partial: 1, formData }, api.updateShopDetail, loading);
+      isOpen.value = false;
+      ElMessage.success('编辑成功');
+      emit('refresh');
+    } else {
+      console.log('error submit!', fields);
+    }
+  });
+};
+
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+};
+
+function replaceCol() {
+  const result = Object.keys(ruleForm).reduce((acc, key) => {
+    if (key in companyOverview) {
+      acc[key] = companyOverview[key];
+    }
+    return acc;
+  }, {} as { [key: string]: any });
+
+  // 处理 contacts 字段
+  if (companyOverview.companyPhoneEmail) {
+    result.contacts = cloneDeep(companyOverview.companyPhoneEmail);  // 深拷贝
+  }
+
+  Object.assign(ruleForm, result);
+}
+</script>
+
+<template>
+  <el-drawer v-model="isOpen" :title="`公司编辑 - ${company}`" size="30%">
+    <el-form
+        ref="ruleFormRef"
+        :model="ruleForm"
+        :rules="rules"
+        class="mx-2.5 mt-2.5"
+        label-width="auto"
+        status-icon>
+      <el-form-item label="公司名称" prop="platformNumber">
+        <el-input v-model="ruleForm.company"/>
+      </el-form-item>
+      <el-form-item label="公司英文名" prop="platformName">
+        <el-input v-model="ruleForm.companyEnglishName"/>
+      </el-form-item>
+      <el-form-item label="公司地址" prop="country">
+        <el-input v-model="ruleForm.address"/>
+      </el-form-item>
+      <el-form-item label="公司法人" prop="brandName">
+        <el-input v-model="ruleForm.juridicalPerson"/>
+      </el-form-item>
+      <el-form-item label="VAT税号" prop="status">
+        <el-input v-model="ruleForm.vatNumber"/>
+      </el-form-item>
+      <el-form-item label="VAT税号公司" prop="platform">
+        <el-input v-model="ruleForm.vatCompany"/>
+      </el-form-item>
+
+      <el-form-item
+          v-for="(contact, index) in ruleForm.contacts"
+          :key="index"
+          :label="'联系方式' + (index + 1)"
+      >
+        <div class="flex gap-2.5 items-start">
+          <el-form-item
+              :prop="'contacts.' + index + '.phone'"
+          >
+            <el-input
+                v-model="contact.phone"
+                placeholder="请输入电话"
+            />
+          </el-form-item>
+          <el-form-item
+              :prop="'contacts.' + index + '.email'"
+              :rules="rules.contacts.email"
+          >
+            <el-input
+                v-model="contact.email"
+                placeholder="请输入邮箱"
+            />
+          </el-form-item>
+          <el-button :icon="Delete" type="danger" @click.prevent="removeContact(contact)">
+            删 除
+          </el-button>
+        </div>
+      </el-form-item>
+      <el-form-item>
+        <div class="flex flex-1 justify-center">
+          <el-button :icon="Plus" type="warning" @click="addContact">新增联系方式</el-button>
+          <el-button :loading="loading" type="primary" @click="submitForm(ruleFormRef)">确 定</el-button>
+          <el-button @click="resetForm(ruleFormRef)">重 置</el-button>
+        </div>
+      </el-form-item>
+    </el-form>
+  </el-drawer>
+</template>
+
+<style scoped>
+
+</style>

+ 3 - 2
src/views/company-information/index.vue

@@ -1,4 +1,5 @@
-<script lang="ts" setup>/**
+<script lang="ts" setup>
+/**
  * @Name: index.vue
  * @Description: 公司信息页面
  * @Author: Cheney
@@ -45,7 +46,7 @@ function handleRefresh() {
           <el-divider class=" text-3xl" direction="vertical"/>
         </div>
         <span>
-           <el-button :icon="Plus" plain type="primary" @click="addCompany">添 加</el-button>
+           <el-button :icon="Plus" type="primary" @click="addCompany">添 加</el-button>
         </span>
       </div>
     </el-card>

+ 74 - 0
src/views/company-information/useColumns.tsx

@@ -0,0 +1,74 @@
+import { useCountryInfoStore } from '/@/stores/countryInfo';
+
+
+const countryInfoStore = useCountryInfoStore();
+
+export const companyColumns = [
+  { type: 'seq', width: 50, align: 'center', fixed: 'left' },
+  {
+    field: 'platform', title: '平台', minWidth: 'auto', align: 'center',
+    slots: {
+      default({ row }: any) {
+        return <span class={ 'font-medium' }>{ row.platform ? row.platform : '--' }</span>;
+      }
+    }
+  },
+  {
+    field: 'platformNumber', title: '平台编号', minWidth: 'auto', align: 'center',
+    slots: {
+      default({ row }: any) {
+        return <span class={ 'font-medium' }>{ row.platformNumber ? row.platformNumber : '--' }</span>;
+      }
+    }
+  },
+  {
+    field: 'platformName', title: '平台名称', minWidth: 'auto', align: 'center',
+    slots: {
+      default({ row }: any) {
+        return <span class={ 'font-medium' }>{ row.platformName ? row.platformName : '--' }</span>;
+      }
+    }
+  },
+  {
+    field: 'status', title: '状态', width: 80, align: 'center',
+    slots: {
+      default({ row }: any) {
+        return (
+            <el-tag
+                class="font-medium"
+                type={ row.status === 1 ? 'success' : 'danger' }
+            >
+              { row.status === 1 ? '启用' : '暂停' }
+            </el-tag>
+        );
+      }
+    }
+  },
+  {
+    field: 'country', title: '国家', minWidth: 'auto', align: 'center',
+    slots: {
+      default({ row }: any) {
+        const country = countryInfoStore.countries.find(c => c.name === row.country);
+        const color = country ? country.color : '#3875F6';
+        return <el-tag effect="plain" round
+                       style={ { color: color, borderColor: color } }>{ row.country ? row.country : '--' }</el-tag>;
+      }
+    }
+  },
+  {
+    field: 'brandName', title: '品牌', minWidth: 'auto', align: 'center',
+    slots: {
+      default({ row }: any) {
+        return <span class={ 'font-medium' }>{ row.brandName ? row.brandName : '--' }</span>;
+      }
+    }
+  },
+  {
+    field: 'line', title: '线路', minWidth: 'auto', align: 'center',
+    slots: {
+      default({ row }: any) {
+        return <span class={ 'font-medium' }>{ row.line ? row.line : '--' }</span>;
+      }
+    }
+  },
+];

+ 1 - 1
src/views/shop-information/components/EditDrawer.vue

@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 /**
  * @Name: EditDrawer.vue
- * @Description:
+ * @Description: 店铺编辑
  * @Author: Cheney
  */
 

+ 1 - 1
src/views/shop-information/components/PlatformDetail.vue

@@ -85,7 +85,7 @@ function handleNavigate(item: any) {
                 style="height: 120px; width: 120px;">
         <template #error>
           <div class="mr-3.5 flex items-center justify-center text-5xl"
-               style="height: 130px; width: 130px; background-color: #f5f5f5">
+               style="height: 100%; width: 100%; background-color: #f5f5f5">
             <el-icon>
               <icon-picture/>
             </el-icon>

+ 4 - 4
src/views/shop-information/components/ShopDetail.vue

@@ -111,7 +111,7 @@ function handleRefresh() {
 
 <template>
   <div class="p-2.5">
-    <el-card v-loading="overviewLoading" body-class="flex items-center" shadow="hover" style="border: none">
+    <el-card v-loading="overviewLoading" body-class="flex items-center gap-10" shadow="hover" style="border: none">
       <div v-if="platformNumber" class="artistic-text-container mr-7 ">
         <div class="artistic-text">
           {{ platformNumber }}
@@ -120,14 +120,14 @@ function handleRefresh() {
       <el-image v-else class="mr-7 rounded-2xl" src="" style="height: 120px; width: 120px; object-fit: contain">
         <template #error>
           <div class="mr-3.5 flex items-center justify-center text-5xl"
-               style="height: 120px; width: 120px; background-color: #f5f5f5">
+               style="height: 100%; width: 100%; background-color: #f5f5f5">
             <el-icon>
               <icon-picture/>
             </el-icon>
           </div>
         </template>
       </el-image>
-      <div class="text-lg mr-10">
+      <div class="text-lg">
         <div class="font-semibold">
           平台编号:
           <span class="font-medium italic ml-1.5" style="color: #64748b"> 
@@ -218,7 +218,7 @@ function handleRefresh() {
         </template>
         <template #toolbar_tools>
           <div class="mr-2.5">
-            <el-button :icon="Edit" plain round type="warning" @click="drawerOpen" :disabled="selectedTab != '1'">编辑</el-button>
+            <el-button :icon="Edit" plain circle type="warning" @click="drawerOpen" :disabled="selectedTab != '1'"></el-button>
           </div>
         </template>
         <template #pager>