瀏覽代碼

提交客户管家公众号的配置

Lijy 1 月之前
父節點
當前提交
e7bc98db54

+ 4 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/api.ts

@@ -16,3 +16,7 @@ export const DEACTIVEUSER = `/user/deactiveUser`
 export const SETACTIVE = `/user/setActive`
 export const SETACTIVE = `/user/setActive`
 export const EXPOERTUSER = `/user/exportUsers`
 export const EXPOERTUSER = `/user/exportUsers`
 export const URL_IMPORTUSER = `/user/importUser`
 export const URL_IMPORTUSER = `/user/importUser`
+export const GET_COMPANY_WEI_XIN = `/wechat-account/getCompanyWeiXin`
+export const SAVE_OR_UPDATE = `/wechat-account/saveOrUpdate`
+export const ONE_CLICK_GENERATION = `/wechat-account/oneClickGeneration`
+export const EXPORT_QR_CODE = `/wechat-account/export`

+ 214 - 26
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/index.vue

@@ -28,7 +28,7 @@
             <el-button :icon="Search" @click="getTableData()" />
             <el-button :icon="Search" @click="getTableData()" />
           </template>
           </template>
         </el-input>
         </el-input>
-        
+
         <div class="formItem mr-6 flex items-center">
         <div class="formItem mr-6 flex items-center">
           <div class="text-nowrap">状态:</div>
           <div class="text-nowrap">状态:</div>
           <el-select v-model="teamForm.status" placeholder="请选择" size="default" style="width: 100px"
           <el-select v-model="teamForm.status" placeholder="请选择" size="default" style="width: 100px"
@@ -43,8 +43,10 @@
             <el-option v-for="item in roleList" :key="item.id" :label="item.rolename" :value="item.id" />
             <el-option v-for="item in roleList" :key="item.id" :label="item.rolename" :value="item.id" />
           </el-select>
           </el-select>
         </div>
         </div>
-        <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1" @click="transitionOperation('exportUser', '')" v-permission="['teamExport']">导出人员</el-button>
-        <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1" @click="dialogFrom.newSyncWithCorpWxDayloadVisable = true">同步企微通讯录</el-button>
+        <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1"
+          @click="transitionOperation('exportUser', '')" v-permission="['teamExport']">导出人员</el-button>
+        <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1"
+          @click="dialogFrom.newSyncWithCorpWxDayloadVisable = true">同步企微通讯录</el-button>
         <el-dropdown v-if="userInfo.userNameNeedTranslate != 1">
         <el-dropdown v-if="userInfo.userNameNeedTranslate != 1">
           <el-button type="primary">
           <el-button type="primary">
             更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
             更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
@@ -52,8 +54,19 @@
           <template #dropdown>
           <template #dropdown>
             <el-dropdown-menu>
             <el-dropdown-menu>
               <el-dropdown-item @click="addPersone(false)" v-permission="['teamAdd']">添加人员</el-dropdown-item>
               <el-dropdown-item @click="addPersone(false)" v-permission="['teamAdd']">添加人员</el-dropdown-item>
-              <el-dropdown-item @click="transitionOperation('exportUser', '')" v-permission="['teamExport']">导出人员</el-dropdown-item>
-              <el-dropdown-item @click="transitionOperation('importUser', '')" v-permission="['teamImport']">批量导入</el-dropdown-item>
+              <el-dropdown-item @click="transitionOperation('exportUser', '')"
+                v-permission="['teamExport']">导出人员</el-dropdown-item>
+              <el-dropdown-item @click="transitionOperation('importUser', '')"
+                v-permission="['teamImport']">批量导入</el-dropdown-item>
+              <el-dropdown-item @click="officialAccountSetting()">
+                {{ officialAccountInformation.id ? '修改公众号配置' : '配置公众号' }}
+              </el-dropdown-item>
+              <el-dropdown-item @click="oneClickGenerationOfQrCode()" v-if="officialAccountInformation.id">
+                一键生成员工二维码
+              </el-dropdown-item>
+              <el-dropdown-item @click="exportQrCode()" v-if="officialAccountInformation.id">
+                导出员工二维码
+              </el-dropdown-item>
             </el-dropdown-menu>
             </el-dropdown-menu>
           </template>
           </template>
         </el-dropdown>
         </el-dropdown>
@@ -67,11 +80,17 @@
             <el-tree style="max-width: 600px" :data="deptList" :props="treeProps" @node-click="treeNode">
             <el-tree style="max-width: 600px" :data="deptList" :props="treeProps" @node-click="treeNode">
               <template #default="{ node, data }">
               <template #default="{ node, data }">
                 <div class="flex justify-between treeContent">
                 <div class="flex justify-between treeContent">
-                  <div class="custom-tree-node" @mouseleave="mouseleave(data,$event)" @mouseover="mouseover(data,$event)">
-                    <div class="treeLabel"><TextTranslation translationTypes="departmentName" :translationValue="node.label"></TextTranslation></div>
+                  <div class="custom-tree-node" @mouseleave="mouseleave(data, $event)"
+                    @mouseover="mouseover(data, $event)">
+                    <div class="treeLabel">
+                      <TextTranslation translationTypes="departmentName" :translationValue="node.label">
+                      </TextTranslation>
+                    </div>
                     <div class="treeIcon nodeEle" id="treeIcon" v-if="data.id > 0">
                     <div class="treeIcon nodeEle" id="treeIcon" v-if="data.id > 0">
-                      <el-link type="primary" :icon="CirclePlus" :underline="false" @click.stop="dialogFromCli('addDeptDialogVisible', data, true)"></el-link>
-                      <el-link type="primary" :icon="Delete" :underline="false" style="margin-left: 6px;" @click.stop="deteleDept(data)"></el-link>
+                      <el-link type="primary" :icon="CirclePlus" :underline="false"
+                        @click.stop="dialogFromCli('addDeptDialogVisible', data, true)"></el-link>
+                      <el-link type="primary" :icon="Delete" :underline="false" style="margin-left: 6px;"
+                        @click.stop="deteleDept(data)"></el-link>
                     </div>
                     </div>
                   </div>
                   </div>
                 </div>
                 </div>
@@ -88,14 +107,26 @@
               <el-table-column type="selection" width="55" />
               <el-table-column type="selection" width="55" />
               <el-table-column label="姓名" property="name" width="150">
               <el-table-column label="姓名" property="name" width="150">
                 <template #default="scope">
                 <template #default="scope">
-                  <TextTranslation translationTypes="userName" :translationValue="scope.row.name"></TextTranslation>
+                  <div class="flex items-center">
+                    <TextTranslation translationTypes="userName" :translationValue="scope.row.name"></TextTranslation>
+                    <template v-if="officialAccountInformation.id && scope.row.wxImgUrlWithTicket">
+                      <el-tooltip class="box-item" effect="dark" content="点击查看销售二维码" placement="top">
+                        <div class="ml-2 cursor-pointer" @click="viewQrCode(scope.row)">
+                          <el-icon color="#075985">
+                            <PictureFilled />
+                          </el-icon>
+                        </div>
+                      </el-tooltip>
+                    </template>
+                  </div>
                 </template>
                 </template>
               </el-table-column>
               </el-table-column>
               <el-table-column label="手机" property="phone"></el-table-column>
               <el-table-column label="手机" property="phone"></el-table-column>
               <el-table-column label="工号" property="jobNumber"></el-table-column>
               <el-table-column label="工号" property="jobNumber"></el-table-column>
               <el-table-column label="部门" property="departmentName">
               <el-table-column label="部门" property="departmentName">
                 <template #default="scope">
                 <template #default="scope">
-                  <TextTranslation translationTypes="departmentName" :translationValue="scope.row.departmentName"></TextTranslation>
+                  <TextTranslation translationTypes="departmentName" :translationValue="scope.row.departmentName">
+                  </TextTranslation>
                 </template>
                 </template>
               </el-table-column>
               </el-table-column>
               <el-table-column label="角色" property="roleName"></el-table-column>
               <el-table-column label="角色" property="roleName"></el-table-column>
@@ -159,7 +190,8 @@
         <el-form ref="deptRuleFormRef" style="max-width: 500px" :model="deptForm" :rules="deptRules" label-width="140px"
         <el-form ref="deptRuleFormRef" style="max-width: 500px" :model="deptForm" :rules="deptRules" label-width="140px"
           size="large" status-icon>
           size="large" status-icon>
           <el-form-item label="部门名称" prop="name">
           <el-form-item label="部门名称" prop="name">
-            <el-input v-model="deptForm.name" placeholder="请输入部门名称" clearable :disabled="userInfo.userNameNeedTranslate == 1" />
+            <el-input v-model="deptForm.name" placeholder="请输入部门名称" clearable
+              :disabled="userInfo.userNameNeedTranslate == 1" />
           </el-form-item>
           </el-form-item>
           <el-form-item label="主要负责人">
           <el-form-item label="主要负责人">
             <!-- <el-select v-model="deptForm.managerId" placeholder="请选择" style="width: 100%" clearable>
             <!-- <el-select v-model="deptForm.managerId" placeholder="请选择" style="width: 100%" clearable>
@@ -171,7 +203,8 @@
             <!-- <el-select v-model="deptForm.otherManagerIds" placeholder="请选择" style="width: 100%" multiple clearable>
             <!-- <el-select v-model="deptForm.otherManagerIds" placeholder="请选择" style="width: 100%" multiple clearable>
               <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
               <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
             </el-select> -->
             </el-select> -->
-            <personnel-search v-model="deptForm.otherManagerIds" :size="''" multiple placeholder="请选择"></personnel-search>
+            <personnel-search v-model="deptForm.otherManagerIds" :size="''" multiple
+              placeholder="请选择"></personnel-search>
           </el-form-item>
           </el-form-item>
         </el-form>
         </el-form>
       </div>
       </div>
@@ -247,13 +280,15 @@
     </el-dialog>
     </el-dialog>
 
 
     <!-- 同步企业微信通讯录 -->
     <!-- 同步企业微信通讯录 -->
-    <el-dialog v-model="dialogFrom.newSyncWithCorpWxDayloadVisable" width="600" :show-close="false" :before-close="handleClose">
+    <el-dialog v-model="dialogFrom.newSyncWithCorpWxDayloadVisable" width="600" :show-close="false"
+      :before-close="handleClose">
       <template #header="{ close, titleId, titleClass }">
       <template #header="{ close, titleId, titleClass }">
         <div class="flex justify-between items-center border-b pb-3 dialog-header">
         <div class="flex justify-between items-center border-b pb-3 dialog-header">
           <h4 :id="titleId">同步企微通讯录</h4>
           <h4 :id="titleId">同步企微通讯录</h4>
           <div class="flex">
           <div class="flex">
             <el-button @click="dialogFrom.newSyncWithCorpWxDayloadVisable = false">取消</el-button>
             <el-button @click="dialogFrom.newSyncWithCorpWxDayloadVisable = false">取消</el-button>
-            <el-button type="primary" :loading="loadingFrom.newSyncWithCorpWxDayloadLoading" @click="newSyncWithCorpWx()">
+            <el-button type="primary" :loading="loadingFrom.newSyncWithCorpWxDayloadLoading"
+              @click="newSyncWithCorpWx()">
               开始同步
               开始同步
             </el-button>
             </el-button>
           </div>
           </div>
@@ -264,6 +299,38 @@
       </div>
       </div>
     </el-dialog>
     </el-dialog>
 
 
+    <!-- 公众号配置 -->
+    <el-dialog v-model="dialogFrom.officialAccountSettingVisable" width="600" :show-close="false"
+      :before-close="handleClose" :close="closeOfficialAccountInformation(officialAccountInformationRef)">
+      <template #header="{ close, titleId, titleClass }">
+        <div class="flex justify-between items-center border-b pb-3 dialog-header">
+          <h4 :id="titleId">公众号配置</h4>
+          <div class="flex">
+            <el-button @click="dialogFrom.officialAccountSettingVisable = false">取消</el-button>
+            <el-button type="primary" :loading="loadingFrom.officialAccountSettingLoading"
+              @click="configureOfficialAccountInformation(officialAccountInformationRef)">
+              配置
+            </el-button>
+          </div>
+        </div>
+      </template>
+      <div class="pt-4 px-12 py-2">
+        <el-form ref="officialAccountInformationRef" style="max-width: 600px" :model="officialAccountInformationFrom"
+          status-icon :rules="officialAccountInformationFromRules" label-width="auto" class="demo-ruleForm">
+          <el-form-item label="名称:" prop="companyName">
+            <el-input v-model.trim="officialAccountInformationFrom.companyName" placeholder="请输入" />
+          </el-form-item>
+          <el-form-item label="appId:" prop="appId">
+            <el-input v-model.trim="officialAccountInformationFrom.appId" placeholder="请输入" />
+          </el-form-item>
+          <el-form-item label="appSecret:" prop="appSecret">
+            <el-input v-model.trim="officialAccountInformationFrom.appSecret" placeholder="请输入" />
+          </el-form-item>
+        </el-form>
+        <el-text class="mx-1" type="warning">请联系客服, 获取ip白名单参数, 配置后方可生效</el-text>
+      </div>
+    </el-dialog>
+
     <!-- 新增人员 -->
     <!-- 新增人员 -->
     <AddPersonnelModal :data="{
     <AddPersonnelModal :data="{
       addPersonnelDialogVisible: dialogFrom.addPersonnelDialogVisible,
       addPersonnelDialogVisible: dialogFrom.addPersonnelDialogVisible,
@@ -275,17 +342,26 @@
     <!-- 批量操作 -->
     <!-- 批量操作 -->
     <BatchOperation :batchData="visibleData" :batchNode="batchTableData" :visibleText="allText.batchText"
     <BatchOperation :batchData="visibleData" :batchNode="batchTableData" :visibleText="allText.batchText"
       :popup="visibleType" :batchOperationVisible="dialogFrom.batchOperationVisible" @close="closeModal" />
       :popup="visibleType" :batchOperationVisible="dialogFrom.batchOperationVisible" @close="closeModal" />
+
+    <!-- 图片预览 -->
+    <el-image-viewer
+      v-if="showPreview"
+      :url-list="previewSrcList"
+      show-progress
+      :initial-index="0"
+      @close="showPreview = false"
+    />
   </div>
   </div>
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
 import { ref, reactive, onMounted, onBeforeMount, inject } from 'vue';
 import { ref, reactive, onMounted, onBeforeMount, inject } from 'vue';
-import { UploadRequestOptions, dayjs, ElLoading } from 'element-plus'
-import { Search, CirclePlusFilled, Edit, CirclePlus, Delete } from '@element-plus/icons-vue'
+import { UploadRequestOptions, dayjs, ElLoading, ElNotification } from 'element-plus'
+import { Search, CirclePlusFilled, Edit, CirclePlus, Delete, PictureFilled } from '@element-plus/icons-vue'
 import { FormInstance, FormRules, ElMessageBox } from 'element-plus'
 import { FormInstance, FormRules, ElMessageBox } from 'element-plus'
 import { useStore } from '@/store/index'
 import { useStore } from '@/store/index'
-import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, DEACTIVEUSER, SETACTIVE, GET_DEPTLIST, BACTHSERROLE, GET_USERLIST, GET_ADDDEPT, ADD_USER, SETRESETPWD, EXPOERTUSER, EDIT_ADDDEPT } from './api'
-import { post, uploadFile } from "@/utils/request";
+import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, DEACTIVEUSER, SETACTIVE, GET_DEPTLIST, BACTHSERROLE, GET_USERLIST, GET_ADDDEPT, ADD_USER, SETRESETPWD, EXPOERTUSER, EDIT_ADDDEPT, GET_COMPANY_WEI_XIN, SAVE_OR_UPDATE, ONE_CLICK_GENERATION, EXPORT_QR_CODE } from './api'
+import { post, uploadFile, downloadFileRequest } from "@/utils/request";
 import { getFromValue, updateDepTreeData, resetFromValue, confirmAction, downloadFile } from '@/utils/tools'
 import { getFromValue, updateDepTreeData, resetFromValue, confirmAction, downloadFile } from '@/utils/tools'
 import { storeToRefs } from 'pinia';
 import { storeToRefs } from 'pinia';
 
 
@@ -310,6 +386,13 @@ interface deptRuleForm { // 部门表单类型
   otherManagerIds: string[] | number[],
   otherManagerIds: string[] | number[],
 }
 }
 
 
+interface officialAccountInformationInterface { // 公众号类型
+  id?: string | number,
+  companyName: string,
+  appId: string,
+  appSecret: string,
+}
+
 // 固定数据
 // 固定数据
 const stateOptions = [{ value: '3', label: '全部' }, { value: '1', label: '在职' }, { value: '0', label: '停用' }]
 const stateOptions = [{ value: '3', label: '全部' }, { value: '1', label: '在职' }, { value: '0', label: '停用' }]
 
 
@@ -325,7 +408,8 @@ const loadingFrom = reactive({ // 所有加载状态
   resignationLoading: false,
   resignationLoading: false,
   exportUserLoading: false,
   exportUserLoading: false,
   importLoading: false,
   importLoading: false,
-  newSyncWithCorpWxDayloadLoading: false
+  newSyncWithCorpWxDayloadLoading: false,
+  officialAccountSettingLoading: false,
 })
 })
 const dialogFrom: any = reactive({ // 所有弹窗状态
 const dialogFrom: any = reactive({ // 所有弹窗状态
   addDeptDialogVisible: false,
   addDeptDialogVisible: false,
@@ -334,7 +418,8 @@ const dialogFrom: any = reactive({ // 所有弹窗状态
   resignationVisible: false,
   resignationVisible: false,
   exportUserVisible: false,
   exportUserVisible: false,
   importVisible: false,
   importVisible: false,
-  newSyncWithCorpWxDayloadVisable: false
+  newSyncWithCorpWxDayloadVisable: false,
+  officialAccountSettingVisable: false,
 });
 });
 const allText = reactive({
 const allText = reactive({
   batchText: '批量操作'
   batchText: '批量操作'
@@ -375,12 +460,61 @@ const treeProps = { // 部门树配置
   children: 'children',
   children: 'children',
   label: 'label',
   label: 'label',
 }
 }
+const officialAccountInformation = ref<officialAccountInformationInterface>({
+  id: '',
+  companyName: '',
+  appId: '',
+  appSecret: '',
+})
+
+const officialAccountInformationFrom = ref<officialAccountInformationInterface>({
+  id: '',
+  companyName: '',
+  appId: '',
+  appSecret: '',
+})
+const officialAccountInformationRef = ref<FormInstance>()
+const showPreview = ref(false)
+const previewSrcList = ref<string[]>([])
 
 
 // 定义校验规则
 // 定义校验规则
 const deptRules = reactive<FormRules<typeof deptForm>>({ // 部门表单校验规则
 const deptRules = reactive<FormRules<typeof deptForm>>({ // 部门表单校验规则
   name: [{ required: true, trigger: 'blur', message: '请输入部门名称' }]
   name: [{ required: true, trigger: 'blur', message: '请输入部门名称' }]
 })
 })
 
 
+const officialAccountInformationFromRules = reactive<FormRules<typeof officialAccountInformation>>({
+  companyName: [{ required: true, trigger: 'blur', message: '请输入' }],
+  appId: [{ required: true, trigger: 'blur', message: '请输入' }],
+  appSecret: [{ required: true, trigger: 'blur', message: '请输入' }]
+})
+
+function viewQrCode(row: any) {
+  const { wxImgUrlWithTicket = '' } = row
+  previewSrcList.value = [wxImgUrlWithTicket]
+  showPreview.value = true
+}
+
+function exportQrCode() {
+  ElNotification({
+    title: '提示',
+    message: '二维码导出中...',
+    type: 'info',
+    showClose: false,
+    duration: 0
+  })
+  downloadFileRequest(EXPORT_QR_CODE, {}).then((blob) => {
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.setAttribute('download', '员工销售二维码.zip'); // 根据需要设定文件名
+    document.body.appendChild(link);
+    link.click();
+    link.remove();
+    window.URL.revokeObjectURL(url);
+    globalPopup?.showSuccess('下载中 请稍后')
+  })
+}
+
 // 同步企业微信通讯录
 // 同步企业微信通讯录
 function newSyncWithCorpWx() {
 function newSyncWithCorpWx() {
   const loading = ElLoading.service({
   const loading = ElLoading.service({
@@ -419,6 +553,58 @@ async function importUser(param: UploadRequestOptions) {
   globalPopup?.showError(res.msg || '')
   globalPopup?.showError(res.msg || '')
 }
 }
 
 
+// 获取公众号配置信息
+function getCompanyWeiXin() {
+  post(GET_COMPANY_WEI_XIN, {}).then((res) => {
+    const { companyName = '', id = '', appId = '', appSecret = '' } = res.data
+    officialAccountInformation.value = {
+      id, companyName, appId, appSecret
+    }
+  })
+}
+
+function oneClickGenerationOfQrCode() {
+  ElNotification({
+    title: '提示',
+    message: '生成二维码中...',
+    type: 'info',
+    showClose: false,
+    duration: 0
+  })
+  post(ONE_CLICK_GENERATION, {}).then(() => {
+    globalPopup?.showSuccess('生成成功')
+    getTableData()
+  })
+}
+
+async function configureOfficialAccountInformation(formEl: FormInstance | undefined) {
+  if (!formEl) return
+  await formEl.validate((valid) => {
+    if (valid) {
+      confirmAction('确定保存当前公众号的配置吗?', '公众号配置', 'warning').then(() => {
+        loadingFrom.officialAccountSettingLoading = true
+        post(SAVE_OR_UPDATE, getFromValue(officialAccountInformationFrom.value)).then(() => {
+          globalPopup?.showSuccess('配置成功')
+          closeModal('officialAccountSettingVisable')
+          getCompanyWeiXin()
+        }).finally(() => {
+          loadingFrom.officialAccountSettingLoading = false
+        })
+      })
+    }
+  })
+}
+
+function closeOfficialAccountInformation(formEl: FormInstance | undefined) {
+  if (!formEl) return
+  formEl.resetFields()
+}
+
+function officialAccountSetting() {
+  officialAccountInformationFrom.value = JSON.parse(JSON.stringify(officialAccountInformation.value))
+  dialogFrom.officialAccountSettingVisable = true
+}
+
 function exportUser() {
 function exportUser() {
   loadingFrom.exportUserLoading = true
   loadingFrom.exportUserLoading = true
   post(EXPOERTUSER, { containInvalid: exportRadio.value }).then((res) => {
   post(EXPOERTUSER, { containInvalid: exportRadio.value }).then((res) => {
@@ -490,7 +676,7 @@ function addPersone(item: any) {
   post(GET_USERINFO, { userId: item.id }).then(res => {
   post(GET_USERINFO, { userId: item.id }).then(res => {
     const { id, name, phone, jobNumber, roleId, departmentCascade, departmentId, inductionDate } = res.data
     const { id, name, phone, jobNumber, roleId, departmentCascade, departmentId, inductionDate } = res.data
     let newData = {
     let newData = {
-      id, name, phone, jobNumber, roleId, 
+      id, name, phone, jobNumber, roleId,
       // departmentId: departmentCascade && departmentCascade.split(',').map(Number).reverse(),
       // departmentId: departmentCascade && departmentCascade.split(',').map(Number).reverse(),
       departmentId: departmentId,
       departmentId: departmentId,
       inductionDate
       inductionDate
@@ -511,7 +697,7 @@ async function personnelModalConfirm(data: any, modelType: string) {
     globalPopup?.showSuccess('添加成功')
     globalPopup?.showSuccess('添加成功')
     getTableData()
     getTableData()
   }).catch(_err => {
   }).catch(_err => {
-    dialogFrom[modelType] = false 
+    dialogFrom[modelType] = false
   })
   })
 }
 }
 
 
@@ -707,6 +893,7 @@ onMounted(() => {
   getUserList()
   getUserList()
   getTableData()
   getTableData()
   getDeptList()
   getDeptList()
+  getCompanyWeiXin()
 });
 });
 </script>
 </script>
 
 
@@ -751,6 +938,7 @@ onMounted(() => {
       align-items: center;
       align-items: center;
       justify-self: flex-end;
       justify-self: flex-end;
     }
     }
+
     .nodeEle {
     .nodeEle {
       display: none;
       display: none;
     }
     }
@@ -763,7 +951,7 @@ onMounted(() => {
 </style>
 </style>
 
 
 <style>
 <style>
-  .temaClass .el-tree-node {
-    padding: 4px 0;
-  }
+.temaClass .el-tree-node {
+  padding: 4px 0;
+}
 </style>
 </style>

+ 53 - 5
fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/request.ts

@@ -30,17 +30,20 @@ instance.interceptors.request.use(
 instance.interceptors.response.use(
 instance.interceptors.response.use(
   (response: AxiosResponse) => {
   (response: AxiosResponse) => {
     // 对响应数据进行处理
     // 对响应数据进行处理
-    if (response.status !== 200 || response.data.code === 'error') {
-      ElNotification.closeAll()
+    if (response.status !== 200 || response.data.code === "error") {
+      ElNotification.closeAll();
       ElNotification({
       ElNotification({
-        message: response.status !== 200 ? showMessage(response.status) : response.data.msg,
+        message:
+          response.status !== 200
+            ? showMessage(response.status)
+            : response.data.msg,
         type: "error",
         type: "error",
       });
       });
     }
     }
     return response;
     return response;
   },
   },
   (error: AxiosError) => {
   (error: AxiosError) => {
-    ElNotification.closeAll()
+    ElNotification.closeAll();
     ElNotification({
     ElNotification({
       message: showMessage(error.request.status), // 传入响应码,匹配响应码对应信息,
       message: showMessage(error.request.status), // 传入响应码,匹配响应码对应信息,
       type: "error",
       type: "error",
@@ -51,7 +54,11 @@ instance.interceptors.response.use(
 );
 );
 
 
 // 封装GET请求
 // 封装GET请求
-export async function get(url: string, params?: any, file: boolean = false): Promise<any> {
+export async function get(
+  url: string,
+  params?: any,
+  file: boolean = false
+): Promise<any> {
   return new Promise((resolve, reject) => {
   return new Promise((resolve, reject) => {
     instance
     instance
       .get(url, { params })
       .get(url, { params })
@@ -114,3 +121,44 @@ export async function uploadFile(url: string, data?: any): Promise<any> {
       });
       });
   });
   });
 }
 }
+
+// 封装文件流请求(下载)
+export async function downloadFileRequest(url: string, params?: any): Promise<Blob> {
+  return new Promise((resolve, reject) => {
+    instance
+      .get(url, {
+        params,
+        responseType: "blob", // 设置响应类型为 blob 以处理文件流
+      })
+      .then((response: AxiosResponse<Blob>) => {
+        // 判断 blob 是否为错误信息(如后端返回错误内容也可能是 JSON)
+        const contentType = response.headers["content-type"];
+        if (contentType && contentType.includes("application/json")) {
+          const reader = new FileReader();
+          reader.onload = () => {
+            const result = reader.result as string;
+            try {
+              const json = JSON.parse(result);
+              ElNotification({
+                message: json.msg || "下载失败",
+                type: "error",
+              });
+              reject(json);
+            } catch (e) {
+              resolve(response.data);
+            }
+          };
+          reader.readAsText(response.data);
+        } else {
+          resolve(response.data);
+        }
+      })
+      .catch((error) => {
+        ElNotification({
+          message: showMessage(error.request.status),
+          type: "error",
+        });
+        reject(error);
+      });
+  });
+}