浏览代码

新增ETA使用管理

chenlei 3 月之前
父节点
当前提交
753f7ccf0e

+ 3 - 2
src/api/api.js

@@ -1,5 +1,5 @@
 //crm
-import { customInterence } from './modules/crmApi';
+import { customInterence, etaTrialInterence } from './modules/crmApi';
 //商家管理
 import {businessCustomInterence} from './modules/businessCustom'
 // 路演权限
@@ -7,5 +7,6 @@ import { roadshowInterence } from './modules/roadshowApi'
 export {
     customInterence,
     businessCustomInterence,
-    roadshowInterence
+    roadshowInterence,
+    etaTrialInterence
 }

+ 83 - 1
src/api/modules/crmApi.js

@@ -12,6 +12,88 @@ const customInterence = {
   checkCompanyInfo: (params) => {
     return get("/custom/check/RepeatCompanyInfo", params);
   },
+  /* 搜索公司qcc KeyWord  */
+  companyQccSearch: (params) => {
+    return get("/custom/potential/company/qccSearch", params);
+  },
+  /* 获取指定权限的销售列表 */
+  getSale: (params) => {
+    // return get('/custom/seller/check/list',params)
+    return get("/custom/seller/check/listV2", params);
+  },
 }
+const etaTrialInterence={
+  /**ETA试用客户列表
+   * PageSize,CurrentIndex,KeyWord
+   * SortParam
+   * SortType : asc正序 desc倒序
+   */
+   getETATrialList:(params)=>{
+     return get('/eta_trial/list',params)
+   },
+  /**非管理员-我的审批列表
+   * 
+   */
+   getApprovalAllList:(params)=>{
+     return get('/eta_trial/apply/myList',params)
+   },
+  /**非管理员-账号列表
+   * 
+   */
+   getApprovalList:(params)=>{
+     return get('/eta_trial/apply/accountlist',params)
+   },
+  /**非管理员-删除申请
+   * ApprovalId
+   */
+   deleteApproval:(params)=>{
+     return post('/eta_trial/apply/del',params)
+   },
+  /**非管理员-撤回申请
+   * Mobile
+   */
+   withdrawApproval:(params)=>{
+     return post('/eta_trial/apply/revoke',params)
+   },
+  /**非管理员-申请启用
+   * UserName,CompanyName,Position,Mobile
+   * ApplyReasons 申请理由
+   */
+   applyEnable:(params)=>{
+     return post('/eta_trial/apply/enable',params)
+   },
+  /**非管理员-新增申请
+   * List[]
+   * List[].UserName 姓名
+   * List[].CompanyName 公司名称
+   * List[].Position 职位
+   * List[].Mobile 手机号
+   */
+   addApproval:(params)=>{
+     return post('/eta_trial/add',params)
+   },
+  /**管理员-审批列表
+   * ApprovalStatus 
+   */
+   getAdminApprovalList:(params)=>{
+     return get('/eta_trial/apply/list',params)
+   },
+  /**管理员-同意申请
+   * ApprovalId
+   */
+   agreeApply:(params)=>{
+     return post('/eta_trial/apply/approval',params)
+   },
+  /**管理员-驳回申请
+   * ApprovalId
+   * RejectReason
+   */
+   rejectApply:(params)=>{
+     return post('/eta_trial/apply/reject',params)
+   },
+   accountTransfer:(params)=>{
+     return post('/eta_trial/account/transfer',params)
+   },
+ }
 
-export { customInterence };
+export { customInterence, etaTrialInterence };

+ 41 - 0
src/router/modules/customer.js

@@ -90,4 +90,45 @@ export default[
       }
     ]
   },
+  {
+    path:'/etaTrial',
+    name:'etaTrial',
+    component:LayoutIndex,
+    meta:{
+      title:'ETA试用管理'
+    },
+    children:[
+      {
+        path: "etaTrialList",
+        component: () => import("@/views/etaTrial/etaTrialList.vue"),
+        name: "etaTrialList",
+        hidden: false,
+        meta: {
+          title:'ETA试用列表'
+        },
+      },
+      {
+        path: "etaApprovalList",
+        component: () => import("@/views/etaTrial/etaTrialList.vue"),
+        name: "etaApprovalList",
+        hidden: false,
+        meta: {
+          pathFrom: "etaTrialList",
+          pathName: "ETA试用",
+          title:'客户列表'
+        },
+      },
+      {
+        path: "etaAddApproval",
+        component: () => import("@/views/etaTrial/addApproval.vue"),
+        name: "etaAddApproval",
+        hidden: false,
+        meta: {
+          pathFrom: "etaTrialList",
+          pathName: "ETA试用",
+          title:'新增申请'
+        },
+      },
+    ]
+  },
 ]

+ 171 - 88
src/views/business_manage/addBusiness.vue

@@ -12,7 +12,7 @@
         <template v-if="current === 0">
             <div class="first-step-form-wrap">
                 <t-form 
-                    :model="firstFormData" 
+                    :data="firstFormData" 
                     :rules="rules"
                     ref="firstFormEl" 
                     label-width="120px"
@@ -20,29 +20,78 @@
                     class="first-step-form"
                 >
                     <div class="form-line">
-                        <t-form-item label="所属区域" prop="areaType">
+                        <t-form-item label="所属区域" name="areaType">
                             <t-radio-group v-model:modelValue="firstFormData.areaType">
-                            <t-radio label="国内">国内</t-radio>
-                            <t-radio label="海外">海外</t-radio>
+                              <t-radio label="国内" value="国内">国内</t-radio>
+                              <t-radio label="海外" value="海外">海外</t-radio>
                             </t-radio-group>
                         </t-form-item>
-                        <t-form-item label="商家名称" prop="name">
-                            <t-input v-model:modelValue="firstFormData.name" placeholder="请输入商家名称"/>
+                        <t-form-item label="商家名称" name="name">
+                            <!-- <t-input v-model:modelValue="firstFormData.name" placeholder="请输入商家名称"/> -->
+                            <autocomplete
+                            ref="autoRef"
+                            v-model="firstFormData.name"
+                            :fetch-suggestions="callbackHandle"
+                            placeholder="请输入商家名称"
+                            @blur="checkCompany"
+                            @select="customNameSelect"
+                            @focus="checkCompanyfocus"
+                            :disabled='inquireSuccess'
+                            clearable
+                            value-key="value"
+                            style="width:360px"
+                            :popper-class="isCheck?'el-autocomplete-none':'el-autocomplete-suggestion-data-entry'"
+                            class="autocomplete-input">
+                                <template #suffix>
+                                  <span 
+                                  
+                                      v-if="firstFormData.name.length > 3" 
+                                      style="color:#409EFF;cursor: pointer;" slot="suffix"  
+                                      @click="searchautoRef"
+                                  > 查询</span>
+                                </template>
+                              <template v-slot:default="{ item }">
+                                <div v-if="item.KeyNo">{{ item.Name }}</div>
+                                <div v-else style="text-align: center;">暂无数据</div>
+                              </template>
+                          </autocomplete>
+                          <el-popover
+                            :visible="showPopover"
+                            ref="popoverRef"
+                            :virtual-ref="autoRef"
+                            trigger="click"
+                            virtual-triggering
+                          >
+                            <div class="popover-box">
+                              <div
+                                v-for="(item, index) in suggestions"
+                                :key="index"
+                                class="popover-item"
+                                @click="customNameSelect(item)"
+                              >
+                                <slot :item="item">{{ item.value }}</slot>
+                              </div>
+                              <div v-if="!suggestions.length" style="text-align: center;">暂无数据</div>
+                            </div>
+                          </el-popover>
                         </t-form-item>
                     </div>
                     <div class="form-line">
-                        <t-form-item label="社会信用码" prop="creditCode">
+                        <t-form-item label="社会信用码" name="creditCode">
                             <t-input v-model:modelValue="firstFormData.creditCode" disabled placeholder="请输入社会信用码"/>
                         </t-form-item>
-                        <t-form-item label="商家地址" prop="address" v-if="firstFormData.areaType === '国内'">
+                        <t-form-item label="商家地址" name="address" v-if="firstFormData.areaType === '国内'">
                             <t-cascader
+                            value-mode="all"
+                            @change="selectRegion"
                             v-model:modelValue="firstFormData.address"
                             :options="locationOptionsReactive"
+                            :keys="locationProps"
                             clearable
                             placeholder="请选择客户地址"
                             />
                         </t-form-item>
-                        <t-form-item label="所属国家" prop="nation" v-else>
+                        <t-form-item label="所属国家" name="nation" v-else>
                             <t-select v-model:modelValue="firstFormData.nation" filterable placeholder="请选择所属国家" style="width: 360px;">
                             <t-option
                                 v-for="item in countryDataReactive"
@@ -59,10 +108,10 @@
                         </t-form-item>
                     </div>
                     <div class="form-line">
-                        <t-form-item label="决策人" prop="decisionMaker">
+                        <t-form-item label="决策人" name="decisionMaker">
                             <t-input v-model:modelValue="firstFormData.decisionMaker" placeholder="请输入决策人"/>
                         </t-form-item>
-                        <t-form-item label="研究团队规模" prop="teamSize">
+                        <t-form-item label="研究团队规模" name="teamSize">
                             <t-select 
                             v-model:modelValue="firstFormData.teamSize" 
                             placeholder="请选择研究团队规模"
@@ -78,10 +127,10 @@
                         </t-form-item>
                     </div>
                     <div class="form-line">
-                        <t-form-item label="资金规模" prop="fundsize">
+                        <t-form-item label="资金规模" name="fundsize">
                             <t-input v-model:modelValue="firstFormData.fundsize" placeholder="请输入资金规模"/>
                         </t-form-item>
-                        <t-form-item label="所属行业" prop="industry">
+                        <t-form-item label="所属行业" name="industry">
                             <t-select 
                             v-model:modelValue="firstFormData.industry" 
                             placeholder="请选择行业" 
@@ -97,21 +146,15 @@
                         </t-form-item>
                     </div>
                     <div class="form-line">
-                        <t-form-item label="用户上限" prop="userMax">
+                        <t-form-item label="用户上限" name="userMax">
                             <t-input v-model:modelValue="firstFormData.userMax" type="number" placeholder="请输入用户上限"/>
                         </t-form-item>
-                        <t-form-item label="所属销售" prop="saller">
+                        <t-form-item label="所属销售" name="saller">
                             <t-cascader
                             v-model:modelValue="firstFormData.saller"
                             :options="salesArr"
                             :show-all-levels="false"
-                            :props="{
-                                expandTrigger: 'hover',
-                                children: 'Child',
-                                emitPath: false,
-                                label: 'AdminName',
-                                value: 'AdminId'
-                            }"
+                            :keys="cascaderProps"
                             filterable
                             clearable
                             placeholder="请选择销售"
@@ -122,65 +165,68 @@
             </div>
         </template>
         <template v-if="current === 1">
+          <div class="second-step-form-wrap">
+            <t-form
+              :data="secondFormData"
+              :rules="rules"
+              ref="formRef"
+              label-width="120px"
+              inline
+              class="second-step-form"
+            >
+              <div class="form-line">
+                <t-form-item label="签约日期" name="signDate">
+                  <t-date-picker
+                    v-model="secondFormData.signDate"
+                    placeholder="选择日期"
+                  />
+                </t-form-item>
+                <t-form-item label="到期日期" name="expirationDate">
+                  <t-date-picker
+                    v-model="secondFormData.expirationDate"
+                    placeholder="选择日期"
+                  />
+                </t-form-item>
+              </div>
+            </t-form>
+          </div>
         </template>
         <template v-if="current === 2">
+
         </template>
-        <!-- <div class="second-step-form-wrap" v-show="step===2">
-            <el-form 
-                :model="secondFormData" 
-                :rules="rules"
-                ref="secondFormEl" 
-                label-width="120px"
-                inline
-                class="second-step-form"
-            >
-                <div class="form-line">
-                    <el-form-item label="签约日期" prop="signDate">
-                        <el-date-picker
-                            v-model="secondFormData.signDate"
-                            type="date"
-                            placeholder="选择日期"
-                            value-format="yyyy-MM-dd"
-                        />
-                    </el-form-item>
-                    <el-form-item label="到期日期" prop="expirationDate">
-                        <el-date-picker
-                            v-model="secondFormData.expirationDate"
-                            type="date"
-                            placeholder="选择日期"
-                            value-format="yyyy-MM-dd"
-                        />
-                    </el-form-item>
-                </div>
-                
-            </el-form>
-        </div> -->
 
         <div class="btns-box">
-            <t-button style="width:80px" theme="primary" v-show="current===0" @click="handleStepSecond">下一步</t-button>
+            <t-button style="width:80px" theme="primary" v-show="current===0" type="submit" @click="handleStepSecond('first')">下一步</t-button>
             <t-button style="width:80px" theme="primary" v-show="current===0" plain @click="$router.back()">取消</t-button>
-            <t-button style="width:80px" theme="primary" v-show="current===1 || current===2" plain @click="step--">上一步</t-button>
-            <t-button style="width:80px" theme="primary" v-show="current===1" plain @click="handleStepSecond">下一步</t-button>
+            <t-button style="width:80px" theme="primary" v-show="current===1 || current===2" plain @click="current--">上一步</t-button>
+            <t-button style="width:80px" theme="primary" v-show="current===1" plain type="submit" @click="handleStepSecond">下一步</t-button>
             <t-button style="width:80px" theme="primary" v-show="current===2" @click="handleAddBusiness">保存</t-button>
         </div>
     </div>
 </template>
 <script setup>
-import { ref, reactive, watch, onMounted } from 'vue';
+import { ref, reactive, watch, onMounted, useTemplateRef } from 'vue';
+import autocomplete from "./components/autocomplete.vue";
 import { customInterence, roadshowInterence, businessCustomInterence } from '@/api/api.js';
-import Steps from "./components/Steps.vue";
 import { locationOptions } from '@/utils/location';
 import countryData from "@/utils/countryData";
+import { ElPopover } from 'element-plus';
+import 'element-plus/es/components/popover/style/css'
 
 // 响应式状态
 const current = ref(0);
+const firstFormEl=useTemplateRef('firstFormEl')
+const formRef = useTemplateRef('formRef');
+const autoRef  = ref(null);
 const countryDataReactive = reactive(countryData);
+const suggestions = ref([]);
+const showPopover = ref(false);
 const locationOptionsReactive = reactive(locationOptions);
 const firstFormData = reactive({
   areaType: '国内',
   name: '',
   creditCode: '',
-  address: '',
+  address: [],
   nation: '',
   decisionMaker: '',
   teamSize: '',
@@ -193,6 +239,19 @@ const secondFormData = reactive({
   signDate: '',
   expirationDate: ''
 });
+const locationProps = reactive({
+    value: 'name',
+    children: 'city',
+    label: 'name',
+});
+const cascaderProps = reactive({
+  expandTrigger: 'hover',
+  children: 'Child',
+  emitPath: false,
+  label: 'AdminName',
+  value: 'AdminId',
+  multiple: true,
+});
 const teamSizeOpts = reactive([
     {
         val:'50人及以下',
@@ -209,8 +268,7 @@ const teamSizeOpts = reactive([
 ]) 
 const tradeArr = ref([]); // 需要在getIndustry方法中赋值
 const salesArr = ref([]); // 需要在getSale方法中赋值
-// 表单验证规则(这里假设你使用的是某个UI库的验证规则,需要替换为实际的验证逻辑)
-const rules = reactive({
+const rules = {
   areaType: [{ required: true, message: '请选择所属区域', trigger: 'change' }],
   name: [{ required: true, message: '请输入商家名称', trigger: 'blur' }],
   creditCode: [{ required: true, message: '请输入社会信用码', trigger: 'blur' }],
@@ -220,9 +278,10 @@ const rules = reactive({
   teamSize: [{ required: true, message: '请选择研究团队规模', trigger: 'change' }],
   industry: [{ required: true, message: '请选择所属行业', trigger: 'change' }],
   userMax: [{ required: true, message: '请输入用户上限', trigger: 'blur' }],
-  saller: [{ required: true, message: '请选择所属销售', trigger: 'change' }]
-});
-// 组件注册(在<script setup>中不需要显式注册,但在单文件组件中需要引入并使用<Steps />)
+  saller: [{ required: true, message: '请选择所属销售', trigger: 'change' }],
+  signDate: [{ required: true, message: '请选择签约日期', trigger: 'change' }],
+  expirationDate: [{ required: true, message: '请选择到期日期', trigger: 'change' }],
+}
 // 生命周期钩子
 onMounted(() => {
   getIndustry();
@@ -263,35 +322,44 @@ const normalizingParams = (params) => {
   };
 };
 
-const handleStepSecond = () => {
-  // 假设你有一个验证方法validateForm,这里需要替换为实际的验证逻辑
-  validateForm(firstFormData).then(valid => {
-    if (valid) {
-      const params = normalizingParams(firstFormData);
-      businessCustomInterence.addBusiness({ IsCheck: true, ...params }).then(res => {
-        if (res.Ret !== 200) return;
-        current.value++;
-      });
+const handleStepSecond = async (stepName) => {
+  let validRes;
+  let params;
+
+  if (stepName === 'first') {
+    validRes = await firstFormEl.value.validate();
+    params = normalizingParams(firstFormData);
+  } else {
+    params = normalizingParams({ ...firstFormData, ...secondFormData });
+    validRes = await formRef.value.validate();
+  }
+
+  if (validRes !== true) return;
+
+  businessCustomInterence.addBusiness({ IsCheck: true, ...params }).then(res => {
+    if (res.Ret === 200) {
+      current.value++;
     }
   });
 };
 
 const handleAddBusiness = () => {
-  // 假设你有一个验证方法validateForm,这里需要替换为实际的验证逻辑
-  validateForm(secondFormData).then(valid => {
-    if (valid) {
-      const params = normalizingParams({ ...firstFormData, ...secondFormData });
-      businessCustomInterence.addBusiness({ IsCheck: false, ...params }).then(res => {
-        if (res.Ret !== 200) return;
-        // 假设你有一个全局的message方法,这里需要替换为实际的消息提示逻辑
-        message.success('添加成功');
-        // 假设你有一个全局的router实例,这里需要替换为实际的路由跳转逻辑
-        router.push('/businessETAList');
-      });
-    }
+  const params = normalizingParams({ ...firstFormData, ...secondFormData });
+  businessCustomInterence.addBusiness({ IsCheck: false, ...params }).then(res => {
+    if (res.Ret !== 200) return;
+    // 假设你有一个全局的message方法,这里需要替换为实际的消息提示逻辑
+    message.success('添加成功');
+    // 假设你有一个全局的router实例,这里需要替换为实际的路由跳转逻辑
+    router.push('/businessETAList');
   });
 };
 
+
+const searchautoRef = () => {
+  showPopover.value = true;
+  autoRef.value.search(firstFormData.name)
+}
+
 const callbackHandle = async (data, cb) => {
   if (data) {
     isCheckCompanyInfo.value = true;
@@ -301,6 +369,7 @@ const callbackHandle = async (data, cb) => {
       isCheckCompanyInfo.value = false;
       if (res.Data && res.Data.length > 0) {
         let arr = res.Data.map(item => ({ value: item.Name, ...item }));
+        suggestions.value = arr;
         cb(arr);
       } else {
         cb([{}]);
@@ -317,6 +386,8 @@ const checkCompanyfocus = () => {
 };
 
 const customNameSelect = (value) => {
+  showPopover.value = false;
+  firstFormData.name = value.value || '';
   firstFormData.creditCode = value.CreditCode;
   setTimeout(async () => {
     checkCompany();
@@ -347,9 +418,9 @@ const checkCompany = () => {
   }, 500);
 };
 
-const selectRegion = (e) => {
-  firstFormData.province = e[0];
-  firstFormData.city = e[1];
+const selectRegion = (e, context) => {
+  firstFormData.province = context.node.getParents()[0].label;
+  firstFormData.city = e;
 };
 
 const getIndustry = () => {
@@ -401,7 +472,11 @@ const router = {
   }
 };
 </script>
-
+<style lang="scss">
+.el-popover {
+  width: 360px !important;
+}
+</style>
 <style lang="scss" scoped>
 .add-business{
     padding:30px;
@@ -448,4 +523,12 @@ const router = {
     width: 200px;
     z-index: 99;
 }
+.popover-box {
+  width: 360px;
+  .popover-item {
+    margin: 10px 0;
+    cursor: pointer;
+  }
+}
+
 </style>

+ 215 - 0
src/views/business_manage/components/autocomplete.vue

@@ -0,0 +1,215 @@
+<template>
+  <div
+    class="autocomplete"
+    v-click-outside="close"
+    aria-haspopup="listbox"
+    role="combobox"
+    :aria-expanded="suggestionVisible"
+    :aria-owns="id"
+  >
+    <t-input
+      ref="inputRef"
+      v-bind="$attrs"
+      @input="handleInput"
+      @change="handleChange"
+      @focus="handleFocus"
+      @blur="handleBlur"
+      @clear="handleClear"
+      @onKeydown.up.native.prevent="highlight(state.highlightedIndex - 1)"
+      @onKeydown.down.native.prevent="highlight(state.highlightedIndex + 1)"
+      @onKeydown.enter.native="handleKeyEnter"
+      @onKeydown.native.tab="close"
+    >
+      <template v-if="$slots.prepend" #prepend>
+        <slot name="prepend"></slot>
+      </template>
+      <template v-if="$slots.append" #append>
+        <slot name="append"></slot>
+      </template>
+      <template v-if="$slots.prefix" #prefix>
+        <slot name="prefix"></slot>
+      </template>
+      <template v-if="$slots.suffix" #suffix>
+        <slot name="suffix"></slot>
+      </template>
+    </t-input>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, watch, onMounted, onBeforeUnmount, unref } from 'vue';
+import debounce from 'lodash/debounce';
+import {ClickOutside as vClickOutside} from 'element-plus'
+// 定义props
+const props = defineProps({
+  valueKey: {
+    type: String,
+    default: 'value',
+  },
+  popperOptions: Object,
+  placeholder: String,
+  clearable: {
+    type: Boolean,
+    default: false,
+  },
+  disabled: Boolean,
+  name: String,
+  size: String,
+  value: String,
+  maxlength: Number,
+  minlength: Number,
+  autofocus: Boolean,
+  fetchSuggestions: Function,
+  triggerOnFocus: {
+    type: Boolean,
+    default: true,
+  },
+  placement: {
+    type: String,
+    default: 'bottom-start',
+  },
+  popperAppendToBody: {
+    type: Boolean,
+    default: true,
+  },
+  highlightFirstItem: {
+    type: Boolean,
+    default: false,
+  },
+});
+
+// 定义emit事件
+const emit = defineEmits(['input', 'change', 'focus', 'blur', 'clear', 'select']);
+// 使用ref和reactive管理状态
+const inputRef = ref(null);
+const suggestionsRef = ref(null);
+const popoverRef = ref()
+const state = reactive({
+  activated: false,
+  suggestions: [],
+  loading: false,
+  highlightedIndex: -1,
+  suggestionDisabled: false,
+});
+
+// 生成唯一ID
+const id = ref(`autocomplete-${Math.random().toString(36).substr(2, 9)}`);
+
+// 计算属性
+const suggestionVisible = computed(() => {
+  return (state.suggestions.length > 0 || state.loading) && state.activated;
+});
+
+// 数据获取函数,使用lodash的debounce进行防抖处理
+const getData = debounce((queryString) => {
+  if (state.suggestionDisabled) return;
+  state.loading = true;
+  props.fetchSuggestions(queryString, (suggestions) => {
+    state.loading = false;
+    if (state.suggestionDisabled) return;
+    if (Array.isArray(suggestions)) {
+      state.suggestions = suggestions;
+      state.highlightedIndex = props.highlightFirstItem ? 0 : -1;
+    } else {
+      console.error('[Autocomplete Error] Suggestions must be an array');
+    }
+  });
+}, 300);
+
+// 处理输入框输入事件
+const handleInput = (value) => {
+  emit('input', value);
+  // search(value);
+};
+
+// 搜索功能
+const search = (value) => {
+  state.activated = true;
+  state.suggestionDisabled = false;
+  if (!props.triggerOnFocus && !value) {
+    state.suggestionDisabled = true;
+    state.suggestions = [];
+    return;
+  }
+  getData(value);
+};
+
+// 处理输入框值变化事件
+const handleChange = (value) => emit('change', value);
+
+// 处理输入框聚焦事件
+const handleFocus = (event) => {
+  emit('focus', event);
+  // if (props.triggerOnFocus) {
+  //   getData(props.value);
+  // }
+};
+
+// 处理输入框失焦事件
+const handleBlur = (event) => emit('blur', event);
+
+// 处理输入框清空事件
+const handleClear = () => {
+  state.activated = false;
+  emit('clear');
+};
+
+// 关闭下拉列表
+const close = () => {
+  state.activated = false;
+  // unref(popoverRef).popperRef?.delayHide?.()
+};
+
+// 处理键盘Enter键事件
+const handleKeyEnter = (event) => {
+  if (suggestionVisible.value && state.highlightedIndex >= 0 && state.highlightedIndex < state.suggestions.length) {
+    event.preventDefault();
+    select(state.suggestions[state.highlightedIndex]);
+  }
+};
+
+// 选择建议项
+const select = (item) => {
+  emit('input', item[props.valueKey]);
+  emit('select', item);
+  state.suggestions = [];
+  state.highlightedIndex = -1;
+};
+
+// 高亮建议项
+const highlight = (index) => {
+  if (!suggestionVisible.value || state.loading) return;
+  if (index < 0) {
+    state.highlightedIndex = -1;
+    return;
+  }
+  if (index >= state.suggestions.length) {
+    index = state.suggestions.length - 1;
+  }
+  state.highlightedIndex = index;
+};
+
+// 监听suggestionVisible的变化
+watch(suggestionVisible, (val) => {
+  if (val && inputRef.value) {
+    // 这里可以添加逻辑来处理suggestionVisible变化时的逻辑,但原始代码中这部分是空的
+  }
+});
+
+// 组件挂载时执行
+onMounted(() => {
+  emit('focus');
+});
+
+// 组件卸载前执行
+onBeforeUnmount(() => {
+  // 清理逻辑,如果有的话
+});
+defineExpose({
+  search
+});
+</script>
+
+<style scoped>
+/* 添加您的样式 */
+</style>

+ 276 - 0
src/views/etaTrial/addApproval.vue

@@ -0,0 +1,276 @@
+<template>
+  <div class="add-approval-wrap">
+   <!--  {{tableData}} -->
+    <el-table :data="tableData" :row-class-name="tableRowClassName" v-loading="pageLoading" border>
+      <!-- 序号 -->
+      <el-table-column
+        type="index"
+        width="50"
+        label="序号"
+        align="center"
+      />
+      <!-- 姓名 -->
+      <el-table-column label="姓名" min-width="100">
+        <template slot-scope="{row}">
+          <el-input v-model="row.UserName" :disabled="row.isApply" placeholder="姓名"></el-input>
+        </template>
+      </el-table-column>
+      <!-- 公司名称 -->
+      <el-table-column label="公司名称" min-width="150">
+        <template slot-scope="{row}">
+          <el-input v-model="row.CompanyName" :disabled="row.isApply" placeholder="公司名称"></el-input>
+        </template>
+      </el-table-column>
+      <!-- 职位 -->
+      <el-table-column label="职位" min-width="100">
+        <template slot-scope="{row}">
+          <el-input v-model="row.Position" :disabled="row.isApply" placeholder="职位"></el-input>
+        </template>
+      </el-table-column>
+      <!-- 手机号码 -->
+      <el-table-column label="手机号码" min-width="120">
+        <template slot-scope="{row}">
+          <el-input v-model.trim="row.Mobile" :disabled="row.isApply" placeholder="手机号码"></el-input>
+        </template>
+      </el-table-column>
+      <!-- 操作 -->
+      <el-table-column label="操作" align="center">
+        <template slot-scope="{row,$index}">
+          <el-button type="text" size="small" @click="addTableData">添加</el-button>
+          <el-button type="text" size="small" class="color-hint" 
+            @click="deleteTableData($index)"
+            v-if="(tableData.length>1&&!row.isApply)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="btn-wrap">
+      <el-button type="primary" @click="handleApprove">提交申请</el-button>
+      <el-button @click="cancelApprove">取 消</el-button>
+    </div>
+    <!-- 提示弹窗 -->
+    <add-apply-hint-dialog 
+      :isAddApplyHintShow.sync="isAddApplyHintShow"
+      :applyInfo="applyInfo" 
+      @overBannedList="checkApproveData([],repeatList,internalList)"
+      @overRepeatList="checkApproveData([],[],internalList)"
+      @applyActiveSuccess="updateTableData"
+      @closeDialog="closeDialog"
+      />
+  </div>
+</template>
+
+<script>
+import addApplyHintDialog from './compontents/addApplyHintDialog.vue';
+import{etaTrialInterence}from '@/api/modules/crmApi.js';
+export default {
+  components: { addApplyHintDialog },
+  data() {
+    return {
+      tableData:[{
+        isApply:false
+      }],
+      isAddApplyHintShow:false,
+      applyInfo:{},
+      repeatList:[],
+      pageLoading:false,
+      internalList:[],
+    };
+  },
+  methods: {
+    addTableData(){
+      this.tableData.push({isApply:false})
+    },
+    deleteTableData(index){
+      this.tableData.splice(index,1)
+    },
+    tableRowClassName({row}){
+      //提交后未通过的 账号已被禁止,账号已重复
+      if(row.isApply===false&&row.isPass===false){
+        return 'warning-row'
+      }
+      //提交前未校验通过的 四项数据未填写或填写错误
+      if(row.isApply===false&&row.isChecked===false){
+        return 'warning-row'
+      }
+      return ''
+    },
+    checkTableData(data){
+      let phoneArr = []
+      for(let i=0;i<data.length;i++){
+        const item = data[i]
+        //已经添加过的不再做校验 因为这条数据不会提交
+        if(item.isApply) continue
+        if((item.UserName&&!item.UserName.length)||!item.UserName){
+          this.$message.warning(`请输入第${i+1}条数据的姓名`)
+          return false
+        }
+        if((item.CompanyName&&!item.CompanyName.length)||!item.CompanyName){
+          this.$message.warning(`请输入第${i+1}条数据的公司名称`)
+          return false
+        }
+        if((item.Position&&!item.Position.length)||!item.Position){
+          this.$message.warning(`请输入第${i+1}条数据的职位`)
+          return false
+        }
+        if((item.Mobile&&!item.Mobile.length)||!item.Mobile){
+          this.$message.warning(`请输入第${i+1}条数据的电话号码`)
+          return false
+        }
+        if(phoneArr.indexOf(data[i].Mobile)===-1){
+          phoneArr.push(data[i].Mobile)
+        }else{
+          //console.log('phoneArr',phoneArr)
+          this.updateTableData(data[i],'update')
+          this.$message.warning(`用户信息重复,请确认`)
+          return false
+        }
+      }
+      return true
+    },
+    async handleApprove(){
+      if(this.pageLoading) return
+      //检查数据
+      if(!this.checkTableData(this.tableData)) return 
+      //提交tableData中 isApply为false的
+      const data = this.tableData.filter((item)=>{return !item.isApply})
+      this.tableData = this.tableData.filter((item)=>{return item.isApply})
+      data.forEach(item=>{
+        delete item.isApply
+        delete item.isPass
+        delete item.isChecked
+      })
+      //说明该页数据全部已提交 直接跳转审批列表
+      if(!data.length){
+        this.$message.success('提交成功')
+        this.$router.push('/etaApprovalList')
+        return
+      }
+      //提交申请 data
+      this.pageLoading = true
+      const res = await etaTrialInterence.addApproval({List:data})
+      this.pageLoading = false
+      if(res.Ret!==200){
+        !this.tableData.length&&this.addTableData()
+        return
+      }
+      const {BannedList,//禁用的列表
+             RepeatList,//重复的列表
+             SuccessList,//成功返回的列表
+             InternalList,//除ETA试用平台其他部门重复的列表
+            } = res.Data
+      //如果这次提交的data全部通过,则跳转回审批列表
+      if(SuccessList&&SuccessList.length===data.length){
+        this.$message.success('提交成功')
+        this.$router.push('/etaApprovalList')
+      }
+      //如果没有全部通过 通过的设置isApply为true 没通过的执行checkApproveData
+      else{
+        const successList = SuccessList?SuccessList.map(item=>{
+          item.isApply = true
+          item.isPass = true
+          return item
+        }):[]
+        const bannedList = BannedList?BannedList.map(item=>{
+          item.isApply = false
+          item.isPass = false
+          return item
+        }):[]
+        const repeatList = RepeatList?RepeatList.map(item=>{
+          item.isApply = false
+          item.isPass = false
+          return item
+        }):[]
+        const internalList = InternalList?InternalList.map(item=>{
+          item.isApply = false
+          item.isPass = false 
+          return item
+        }):[]
+        this.tableData = this.tableData.concat(successList,bannedList,repeatList,internalList)
+        !this.tableData.length&&this.addTableData()
+        this.checkApproveData(bannedList,repeatList,internalList)
+      }
+    },
+    checkApproveData(BannedList=[],RepeatList=[],InternalList=[]){
+      if(BannedList.length){
+        this.applyInfo.applyType = 0
+        this.applyInfo.applyData = BannedList
+        this.repeatList = RepeatList
+        this.internalList = InternalList
+      }else if(RepeatList.length){
+        //展示全部信息
+        this.applyInfo.applyType = 1
+        this.applyInfo.applyData = RepeatList
+        this.internalList = InternalList
+      }
+      if(!BannedList.length&&!RepeatList.length){
+        if(InternalList.length){
+          //展示轻提示
+          this.$message.error('用户信息重复,请联系管理员或技术部门')
+        }
+        return 
+      }
+      this.$nextTick(()=>{
+        this.isAddApplyHintShow = true
+      })
+    },
+    updateTableData(data,type='remove'){
+      //console.log('update',data)
+      //手机号作为标识
+      const index = this.tableData.findLastIndex((item)=>{return item.Mobile===data.Mobile})
+      const tableItem = this.tableData[index]
+      if(type==='remove'){
+        /* tableItem.isApply = true
+        tableItem.isPass = true
+        this.tableData.splice(index,1,tableItem) */
+        this.tableData.splice(index,1)
+        //如果删掉的是最后一个
+        if(!this.tableData.length){
+          this.addTableData()
+        }
+      }else{
+        tableItem.isChecked=false
+        this.tableData.splice(index,1,tableItem)
+      }      
+    },
+    cancelApprove(){
+      //返回ETA试用列表
+      this.$router.push('/etaTrialList')
+    },
+    closeDialog(){
+      this.isAddApplyHintShow = false
+    }
+  },
+  mounted(){
+    if(sessionStorage.getItem('applyInfo')){
+      const applyInfo = JSON.parse(sessionStorage.getItem('applyInfo'))
+      sessionStorage.removeItem('applyInfo')
+      const data = applyInfo.applyData[0]
+      data.isApply = false
+      //this.tableData.unshift(data)
+      this.tableData=[data]
+    }
+  }
+};
+</script>
+
+<style lang="scss">
+.add-approval-wrap{
+  .el-table .warning-row {
+    background: #FEF0F0;
+  }
+}
+</style>
+<style scoped lang="scss">
+.add-approval-wrap{
+  padding:30px;
+  background-color: #fff;
+  border-radius: 4px;
+  .color-hint{
+    color: red;
+  }
+  .btn-wrap{
+    margin-top:120px;
+    text-align: center;
+  }
+}
+</style>

+ 182 - 0
src/views/etaTrial/compontents/addApplyHintDialog.vue

@@ -0,0 +1,182 @@
+<template>
+<!-- 新增申请 提示弹窗 弹窗 -->
+  <div class="add-apply-hint-dialog">
+    <el-dialog
+      v-if="isAddApplyHintShow"
+      :visible.sync="isAddApplyHintShow"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      title="提示"
+      @close="handleApprove(false)"
+      width="889px"
+      v-dialogDrag
+      center
+    >
+      <div class="dialog-container">
+        <p class="hint">{{hintText}}</p>
+        <div class="table-wrap">
+          <el-table :data="tableData" border v-loading="tableLoading">
+            <el-table-column v-for="column in columnList" :key="column.label"
+              align="center"
+              :prop="column.key"
+              :label="column.label"
+              :min-width="column.minWidth"
+            />
+          </el-table>
+        </div>
+        <div class="apply-reason" v-if="applyInfo.applyType===0">
+          <p>申请理由</p>
+          <textarea
+            placeholder="请输入申请理由"
+            v-model="applyReason"
+            :rows="3"
+          />
+        </div>
+      </div>
+      <div class="foot-container">
+        <template v-if="applyInfo.applyType===0">
+          <el-button type="primary" @click="handleApprove">申请启用</el-button>
+          <el-button @click="handleApprove(false)">取 消</el-button>
+        </template>
+        <template v-else>
+          <el-button type="primary" @click="closeDialog">知道了</el-button>
+        </template>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import{etaTrialInterence}from '@/api/modules/crmApi.js';
+import {applyApprovalList,textMap} from "../config"
+export default {
+  props:{
+    isAddApplyHintShow:{//弹窗显示
+      type:Boolean,
+      default:false
+    },
+    applyInfo:{//申请信息 
+      type:Object,
+      default:()=>{
+        return {
+          applyType:1,//0 账号禁用 1 信息重复
+          applyData:[]
+        }
+      }
+    }
+  },
+  computed:{
+  },
+  watch:{
+    isAddApplyHintShow(val){
+      if(val){
+        this.getTableData()
+        this.hintText = textMap[this.applyInfo.applyType]
+      }
+    }
+  },
+  data() {
+    return {
+      tableData:[],
+      applyData:[],
+      dataIndex:0,
+      columnList:applyApprovalList,
+      applyReason:'',
+      tableLoading:false,
+      hintText:'',
+    };
+  },
+  methods: {
+    closeDialog(){
+      //清空数据什么的
+      this.applyReason=''
+      this.tableData=[]
+      this.applyData=[]
+      this.dataIndex=0
+      this.$emit("closeDialog");
+      if(this.applyInfo.applyType===0){
+        this.$emit('overBannedList')
+        return
+      }
+      if(this.applyInfo.applyType===1){
+        this.$emit('overRepeatList')
+        return
+      }
+      
+    },
+    getTableData(){
+      //console.log('getTableData:applyType',this.applyInfo.applyType)
+      this.tableLoading = true
+      //如果是申请启用,则只展示一条数据
+      if(this.applyInfo.applyType===0){
+        this.applyData = this.applyInfo.applyData
+        this.tableData = [this.applyData[0]]
+        this.dataIndex = 0
+      }
+      //如果是申请信息重复,则展示全部数据
+      else{
+        this.tableData = this.applyInfo.applyData
+        this.dataIndex = 0
+      }
+      this.$nextTick(()=>{
+        this.tableLoading=false
+      })
+    },
+    async handleApprove(getNext=true){
+      if(getNext){
+        // if(!this.applyReason.length){
+        //   this.$message.warning('请输入申请理由')
+        //   return
+        // }
+        const {UserName,CompanyName,Position,Mobile} = this.applyData[this.dataIndex]
+        //调用申请接口
+        const res = await etaTrialInterence.applyEnable({
+          UserName,CompanyName,Position,Mobile,
+          ApplyReasons:this.applyReason
+        })
+        if(res.Ret!==200) return 
+        this.$message.success('提交成功')
+        //申请成功 在父页面将该记录删除
+        this.$emit('applyActiveSuccess',this.applyData[this.dataIndex]) 
+      }
+      this.applyReason=''
+      this.getNextTableData()
+    },
+    getNextTableData(){
+      this.dataIndex++
+      const length = this.applyData.length
+      if(length-1>=this.dataIndex){
+        this.tableData = [this.applyData[this.dataIndex]]
+      }else{
+        this.closeDialog()
+      }
+    }
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.add-apply-hint-dialog{
+  .dialog-container{
+    .table-wrap{
+      margin-top:20px;
+    }
+    .apply-reason{
+      margin-top:30px;
+    }
+    textarea{
+      width:100%;
+      margin-top: 10px;
+      padding:10px;
+      border-radius: 4px;
+      box-sizing: border-box;
+      border-color: #DCDFE6;
+    }
+  }
+  .foot-container{
+    text-align: center;
+    padding-bottom: 40px;
+    margin-top: 60px;
+  }
+}
+</style>

+ 199 - 0
src/views/etaTrial/compontents/applyApprovalDialog.vue

@@ -0,0 +1,199 @@
+<template>
+<!-- 申请账号审批/申请启用审批 弹窗 -->
+  <div class="apply-approval-dialog">
+    <el-dialog
+      :visible.sync="isApplyApprovalDialogShow"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      :title="`申请${applyInfo.applyType===0?'启用':'账号'}审批`"
+      @close="closeDialog"
+      width="889px"
+      v-dialogDrag
+      center
+    >
+      <div class="dialog-container">
+        <div class="table-wrap">
+          <el-table :data="tableData" border v-loading="tableLoading">
+            <el-table-column v-for="column in columnList" :key="column.label"
+              align="center"
+              :prop="column.key"
+              :label="column.label"
+              :min-width="column.minWidth"
+            />
+          </el-table>
+        </div>
+        <div class="apply-reason" v-if="applyInfo.applyType===0">
+          <p>申请理由</p>
+          <textarea
+            v-model="applyInfo.applyData[0].ApplyReasons"
+            disabled
+            :rows="3"
+          />
+        </div>
+        <div class="apply-form">
+          <div class="apply-status">
+            <span>审批状态</span>
+             <el-radio-group v-model="applyStatus">
+              <el-radio :label="1">通过</el-radio>
+              <el-radio :label="2" class="color-hint">驳回</el-radio>
+            </el-radio-group>
+          </div>
+          <div class="reject-reason" v-if="applyStatus===2">
+            <span>驳回理由</span>
+            <textarea
+              v-model="rejectReason"
+              placeholder="请输入驳回理由"
+              :rows="3"
+            />
+          </div>
+        </div>
+      </div>
+      <div class="foot-container">
+        <el-button type="primary" @click="handleApprove">确 定</el-button>
+        <el-button @click="closeDialog">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {applyApprovalList} from "../config";
+import{etaTrialInterence}from '@/api/modules/crmApi.js';
+export default {
+  props:{
+    isApplyApprovalDialogShow:{//弹窗显示
+      type:Boolean,
+      default:false
+    },
+    applyInfo:{//申请信息 applyType 0 申请启用 1 申请账号
+      type:Object,
+      default:()=>{
+        return {
+          applyType:0,
+          applyData:[{ApplyReasons:''}]
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      applyStatus:1,//审批状态
+      rejectReason:'',//驳回理由
+      columnList:applyApprovalList,//表格列
+      tableLoading:false,
+      tableData:[]
+    };
+  },
+  watch:{
+    isApplyApprovalDialogShow(val){
+      if(val){
+        this.getTableData()
+      }
+    }
+  },
+  methods: {
+    async handleApprove(){
+      //提交这条审批
+      let res = null
+      if(this.applyStatus===1){
+        res = await etaTrialInterence.agreeApply({
+          ApprovalId:this.tableData[0].ApprovalId
+        })
+      }else{
+        if(!this.rejectReason.length){
+          this.$message.warning('请填写驳回理由')
+          return
+        }
+        res = await etaTrialInterence.rejectApply({
+          ApprovalId:this.tableData[0].ApprovalId,
+          RejectReason:this.rejectReason
+        })
+      }
+      if(res.Ret!==200) return 
+      this.$message.success(this.applyStatus===1?'通过成功':'驳回成功')
+      this.$emit('approved')
+      this.closeDialog()
+    },
+    closeDialog(){
+      //清空数据什么的
+      this.applyStatus=1
+      this.rejectReason=''
+      this.$emit("update:isApplyApprovalDialogShow", false);
+    },
+    getTableData(){
+      this.tableLoading = true
+      this.tableData = this.applyInfo.applyData
+      this.$nextTick(()=>{
+        this.tableLoading=false
+      })
+    },
+  },
+};
+</script>
+<style lang="scss">
+.apply-approval-dialog{
+  .apply-status{
+    .el-radio{
+      //更改单选框的样式
+    .el-radio__inner{
+      background: transparent;
+      &::after{
+        width:6px;
+        height:6px;
+        background-color: #409EFF;
+      }
+    }
+    }
+  }
+  .color-hint{
+    //更改驳回的样式
+    &.is-checked{
+      .el-radio__inner{
+        border-color: #C54322;
+        &::after{
+          background-color: #C54322;
+        }
+      }
+      .el-radio__input{
+        &.is-checked{//我真服了
+          +.el-radio__label{
+            color: #C54322;
+          }
+        }
+      }
+    }
+  }
+}
+</style>
+<style scoped lang="scss">
+.apply-approval-dialog{
+  .dialog-container{
+    /* .table-wrap{} */
+    .apply-reason{
+      margin-top:30px;
+      padding-bottom:30px;
+      border-bottom: 1px dashed #DCDFE6;
+    }
+    .apply-form{
+      margin-top:30px;
+      /* .apply-status{} */
+      .reject-reason{
+        margin-top:30px;
+      }
+    }
+    textarea{
+      width:100%;
+      margin-top: 10px;
+      padding:10px;
+      border-radius: 4px;
+      box-sizing: border-box;
+      border-color: #DCDFE6;
+    }
+  }
+  .foot-container{
+    text-align: center;
+    padding-bottom: 40px;
+    margin-top: 60px;
+  }
+}
+</style>

+ 127 - 0
src/views/etaTrial/compontents/move.vue

@@ -0,0 +1,127 @@
+<template>
+<!-- 新增申请 提示弹窗 弹窗 -->
+  <div class="move-dialog">
+    <el-dialog
+      :visible.sync="isMoveShow"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      :title="title"
+      @close="handleMove(false)"
+      width="530px"
+      v-dialogDrag
+      center
+    >
+      <div class="dialog-container">
+        <el-form ref="form" :model="form" label-width="150px">
+          <el-form-item label="移动到">
+            <el-cascader
+              v-model="value"
+              placeholder="请选择用户"
+              style="width:200px;margin-right:10px;margin-bottom:8px;"
+              :options="salesArr"
+              :props="defaultSalesProps"
+              :show-all-levels="false"
+              :key="modifySales"
+              collapse-tags
+              clearable
+              filterable
+              @change="changeSales">
+            </el-cascader>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="foot-container">
+        <el-button @click="handleMove(false)">取 消</el-button>
+        <el-button type="primary" @click="handleMove">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {titleMap} from "../config"
+export default {
+  props:{
+    isMoveShow:{//弹窗显示
+      type:Boolean,
+      default:false
+    },
+    moveInfo:{//申请信息 
+      type:Object,
+      default:()=>{
+        return {
+          type:1,//1 移动 2 批量移动
+          salesArr:[],//销售列表
+          selectArr:[]//申请列表
+        }
+      }
+    }
+  },
+  computed:{
+  },
+  watch:{
+    isMoveShow(val){
+      if(val){
+
+        this.modifySales++
+        this.title = titleMap[this.moveInfo.type]
+        this.salesArr = this.moveInfo.salesArr
+        this.value = ''
+        this.$nextTick(() => {
+          this.$refs.form.clearValidate();
+          this.$refs.form.resetFields();
+        })
+      }
+    }
+  },
+  data() {
+    return {
+      title:'',
+      value:'',
+      defaultSalesProps:{
+				label:'RealName',
+				children:'ChildrenList',
+				value:'AdminId'
+			},//级联配置
+      modifySales:0,//用于重新渲染选择销售级联选择窗
+    };
+  },
+  methods: {
+    handleMove(isConfirm) {
+      const data = {
+        value:this.value,
+        type: this.moveInfo.type,
+        selectArr:this.moveInfo.selectArr
+      }
+      if(isConfirm){
+        this.$emit('moveConfirm', data)
+      }else{
+        this.$emit('closeMove')
+      }
+    }
+  },
+};
+</script>
+
+<style lang="scss">
+.move-dialog{
+  .dialog-container{
+    .el-input--suffix {
+      width: 100%;
+    }
+  }
+}
+
+</style>
+<style scoped lang="scss">
+.move-dialog{
+  .dialog-container{
+    margin-top: 40px;
+  }
+  .foot-container{
+    text-align: center;
+    padding-bottom: 40px;
+    margin-top: 60px;
+  }
+}
+</style>

+ 186 - 0
src/views/etaTrial/config.js

@@ -0,0 +1,186 @@
+//ETA试用列表 表格column 和mock数据
+
+//ETA试用列表
+export const etaTrialColumn = [
+  {
+    colKey:'UserName',
+    title:'姓名'
+  },
+  {
+    colKey:'CompanyName',
+    title:'公司名称'
+  },{
+    colKey:'Position',
+    title:'职位',
+    minWidth:'50'
+  },{
+    colKey:'Seller',
+    title:'申请人',
+    minWidth:'50'
+  },{
+    colKey:'Expiration',
+    title:'账号到期时长',
+    minWidth:'80'
+  },{
+    colKey:'ModifyTime',
+    title:'账号更新时间',
+    minWidth:'120'
+  },{
+    colKey:'LastLoginTime',
+    title:'最近一次登录时间',
+    minWidth:'120'
+  },{
+    colKey:'LastLoginDuration',
+    title:'最近一次登录时长',
+  },{
+    colKey:'LoginNum',
+    title:'累计登录次数',
+  },{
+    colKey:'ActiveTime',
+    title:'累计活跃时长',
+  },{
+    colKey:'IndexNum',
+    title:'累计添加指标',
+    minWidth:'80'
+  },
+  {
+    colKey:'ChartNum',
+    title:'累计添加图表',
+    minWidth:'80'
+  },
+  {
+    colKey:'InterestModule',
+    title:'感兴趣模块',
+    minWidth:'140'
+  },
+  {
+    align: 'center', colKey: 'opt', title: '操作'
+  }
+]
+
+//管理员-审批列表 非管理员-我的审批
+export const adminApprovalList=[
+  {
+    colKey:'UserName',
+    title:'姓名'
+  },
+  {
+    colKey:'CompanyName',
+    title:'公司名称'
+  },{
+    colKey:'Position',
+    title:'职位',
+    minWidth:'50'
+  },
+  {
+    colKey:'Mobile',
+    title:'手机号码',
+  },{
+    colKey:'Seller',
+    title:'申请人',
+    minWidth:'50'
+  },{
+    colKey:'ModifyTime',
+    title:'提交申请时间',
+    minWidth:'120'
+  },{
+    colKey:'ApprovalContent',
+    title:'待审内容',
+  },{
+    colKey:'ApprovalStatus',
+    title:'当前状态',
+  },
+  {
+    align: 'center', colKey: 'opt', title: '操作'
+  }
+]
+
+//非管理员-账号列表
+export const approvedList=[
+  {
+    colKey:'UserName',
+    title:'姓名'
+  },
+  {
+    colKey:'CompanyName',
+    title:'公司名称'
+  },{
+    colKey:'Position',
+    title:'职位',
+    minWidth:'50'
+  },
+  {
+    colKey:'Mobile',
+    title:'手机号码',
+  },{
+    colKey:'Account',
+    title:'账号',
+    minWidth:'50'
+  },{
+    colKey:'Password',
+    title:'密码',
+    minWidth:'50'
+  },{
+    colKey:'Enabled',
+    title:'用户状态',
+  },{
+    colKey:'Expiration',
+    title:'账号到期时长',
+    minWidth:'80'
+  },{
+    colKey:'ModifyTime',
+    title:'更新时间',
+    minWidth:'80'
+  },
+  {
+    align: 'center', colKey: 'opt', title: '操作'
+  }
+]
+
+//申请启用审批/申请账号审批
+export const applyApprovalList=[
+  {
+    colKey:'UserName',
+    title:'姓名'
+  },{
+    colKey:'CompanyName',
+    title:'公司名称'
+  },{
+    colKey:'Position',
+    title:'职位'
+  },{
+    colKey:'Mobile',
+    title:'手机号'
+  },{
+    colKey:'Seller',
+    title:'申请人'
+  },
+  {
+    align: 'center', colKey: 'opt', title: '操作'
+  }
+]
+
+//审批列表-当前状态
+/* export const ApprovalStatus = {
+  0:'未审批',
+  1:'已审批',
+  2:'已撤回',
+  3:'已驳回'
+} */
+export const ApprovalStatus={
+  '待审批':0,
+  '已审批':1,
+  '已撤回':2,
+  '驳回':3
+}
+//启用,账号重复提示弹窗
+export const textMap = {
+  0:'该用户账号已禁用,是否申请启用',
+  1:'该用户信息已提交申请 ,请勿重复提交'
+}
+//移动、批量移动弹窗
+export const titleMap = {
+  1:'移动',
+  2:'批量移动'
+}
+

+ 640 - 0
src/views/etaTrial/etaTrialList.vue

@@ -0,0 +1,640 @@
+<template>
+  <!-- ETA试用列表+审批列表 -->
+  <div class="eta-trial-list">
+    <div class="table-select">
+      <div class="btn-list">
+        <template v-if="false">
+          <!-- !Role.includes('admin') -->
+          <!-- 管理员-ETA试用列表 -->
+          <template v-if="route.path === '/etaTrialList'">
+            <t-button type="primary" @click="changePath('/etaApprovalList')">审批列表</t-button>
+            <div class="approval-hint" v-if="approvalNum">
+              ·{{ approvalNum }}条申请记录待审批
+            </div>
+            <t-button type="primary" @click="toQuestionnaireSurvey" style="margin-left: 30px;">问卷调研</t-button>
+          </template>
+          <!-- 管理员-审批列表 -->
+          <template v-if="route.path === '/etaApprovalList'">
+            <t-select v-model="approvalState" placeholder="请选择" @change="selectHandle">
+              <t-option
+                v-for="item in approvalStateArr"
+                :key="item.key"
+                :label="item.label"
+                :value="item.key"
+              ></t-option>
+            </t-select>
+          </template>
+        </template>
+        <template v-else>
+          <!-- 非管理员-ETA试用列表 -->
+          <template v-if="route.path === '/etaTrialList'">
+            <t-button type="primary" @click="changePath('/etaAddApproval')">新增申请</t-button>
+            <t-button type="primary" plain @click="changePath('/etaApprovalList')" style="margin-left: 30px;">客户管理</t-button>
+            <t-button type="primary" @click="toQuestionnaireSurvey" style="margin-left: 30px;">问卷调研</t-button>
+            <t-checkbox v-model="onlyMine" @change="onlyMineChange" style="margin-left: 30px;">我申请的</t-checkbox>
+          </template>
+          <!-- 非管理员-我的审批+账号列表 -->
+          <template v-if="route.path === '/etaApprovalList'">
+            <div class="tips">*账号用于登录ETA试用平台:https://exptest.hzinsights.com/</div>
+            <div class="right-header">
+              <span>已选{{ selectedTotal }}</span>
+              <t-checkbox :indeterminate="isIndeterminate" v-model="isCheckAll" @change="listCheckAllChange" style="margin-left: 40px;">列表全选</t-checkbox>
+            </div>
+          </template>
+        </template>
+      </div>
+      <div class="search-wrap">
+        <template v-if="route.path === '/etaApprovalList'">
+          <t-button type="primary" @click="batchMove">批量移动</t-button>
+          <t-button type="primary" @click="batchOperate">一键启用</t-button>
+        </template>
+        <t-input
+          v-model="searchText"
+          placeholder="姓名/公司名称"
+          @input="searchHandle"
+          style="width: 400px; margin-left: 20px;"
+        >
+        <template #prefixIcon><SearchIcon /></template>
+      </t-input>
+      </div>
+    </div>
+    <div class="table-wrap">
+      <t-table :data="tableData" @sort-change="sortChangeHandle" :columns="columnList" ref="dataRef" border v-loading="tableLoading" @select="selectHandles" @select-all="selectAllHandle" @selection-change="selectionChange">
+        <!-- 多选 -->
+        <!-- <t-table-column align="center" type="selection" width="55" v-if="route.path === '/etaApprovalList'">
+        </t-table-column> -->
+       
+        <!-- <template #approveType="{ row }">
+          <span >
+            {{ row['approveType'] === 0 ? '申请账号' : '申请启用' }}
+          </span>
+        </template> -->
+        <template #Enabled="{ row }" >
+          <span :class="{'color-hint': row['Enabled'] === 0}">
+              {{ row['Enabled'] === 0 ? '禁用' : '启用' }}
+            </span>
+        </template>
+        <template #cellEmptyContent="{ row }">
+            <!-- 非管理员-账号列表的操作: 申请启用 -->
+            <div>
+              <t-button type="text" size="small" @click="Move(row)">移动</t-button>
+              <t-button type="text" size="small" v-if="row.Enabled === 0" @click="handleOperate('active', row)">申请启用</t-button>
+            </div>
+            <!-- 非管理员-我的审批操作: 撤回,重新申请,删除,驳回理由-->
+            <div v-if="!Role.includes('admin') && listType === 'all'">
+              <t-button type="text" size="small" v-if="ApprovalStatus[row.ApprovalStatus] === 0" @click="handleOperate('withdraw', row)">撤回</t-button>
+              <t-button type="text" size="small" v-if="ApprovalStatus[row.ApprovalStatus] >= 2" @click="handleOperate('apply', row)">重新申请</t-button>
+              <t-button type="text" size="small" v-if="ApprovalStatus[row.ApprovalStatus] === 3" @click="handleOperate('checkReplay', row)">驳回理由</t-button>
+              <t-button type="text" size="small" v-if="ApprovalStatus[row.ApprovalStatus] === 2" class="color-hint" @click="handleOperate('delete', row)">删除</t-button>
+              <!-- 已审批通过的:查看密码 -->
+              <t-button type="text" size="small" v-if="ApprovalStatus[row.ApprovalStatus] === 1" @click="handleOperate('showDetail', row)">账号密码</t-button>
+            </div>
+            <!-- 管理员-审批列表操作: 审批-->
+            <!-- <template v-if="Role.includes('admin')">
+              <t-button type="text" size="small" v-if="ApprovalStatus[row.ApprovalStatus] === 0" @click="handleOperate('approve', row)">审批</t-button>
+            </template> -->
+        </template>
+      </t-table>
+      <t-pagination
+        layout="total,prev,pager,next,jumper"
+        background
+        :current-page="currentPage"
+        @current-change="handleCurrentChange"
+        :page-size="pageSize"
+        :total="total"
+        style="text-align:right;margin-top:30px;"
+      ></t-pagination>
+    </div>
+    <!-- 申请账号审批/申请启用审批 弹窗 -->
+    <!-- <apply-approval-dialog
+      :isApplyApprovalDialogShow.sync="isApplyApprovalDialogShow"
+      :applyInfo="applyInfo"
+      @approved="getTableData"
+    ></apply-approval-dialog> -->
+    <!-- 申请启用 弹窗 -->
+    <!-- <add-apply-hint-dialog
+      :isAddApplyHintShow.sync="isAddApplyHintShow"
+      :applyInfo="applyInfo"
+      @applyActiveSuccess="getTableData"
+      @closeDialog="closeDialog"
+    ></add-apply-hint-dialog> -->
+    <!-- 移动弹窗 -->
+    <!-- <move
+      :isMoveShow.sync="isMoveShow"
+      :moveInfo="moveInfo"
+      @moveConfirm="moveConfirm"
+      @closeMove="closeMove"
+    ></move> -->
+    <!-- 查看账号密码弹窗 -->
+    <t-dialog
+      v-if="showDetailDialogShow"
+      :visible="showDetailDialogShow"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      :title="`${applyInfo.applyData[0].UserName}——账号密码`"
+      width="889px"
+      draggable
+      center
+    >
+      <div class="apply-detail">
+        <p>公司名称:{{ applyInfo.applyData[0].CompanyName }}</p>
+        <p>账号:{{ applyInfo.applyData[0].Account }}</p>
+        <p>密码:{{ applyInfo.applyData[0].Password }}</p>
+        <div class="button">
+          <t-button type="primary" @click="showDetailDialogShow = false">知道了</t-button>
+        </div>
+      </div>
+    </t-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, watch, onMounted } from 'vue';
+// import { TButton, TSelect, TOption, TTable, TTableColumn, TPagination, TDialog } from 'tdesign-vue-next';
+import { SearchIcon } from 'tdesign-icons-vue-next';
+import { etaTrialColumn, adminApprovalList, approvedList, ApprovalStatus } from './config';
+import { etaTrialInterence } from '@/api/modules/crmApi.js';
+import { customInterence } from '@/api/api.js';
+import { useRoute, useRouter } from 'vue-router'
+const router=useRouter()
+const route=useRoute()
+// 响应式数据
+const currentPath = ref('');
+const approvalNum = ref(0);
+const searchText = ref('');
+const onlyMine = ref(false);
+const listType = ref('approved');
+const approvalState = ref();
+const approvalStateArr = reactive([
+  { key: 2, label: '待审批' },
+  { key: 3, label: '已审批' },
+  { key: 1, label: '全部' },
+]);
+// const ApprovalStatus = reactive(ApprovalStatus);
+const canEdit = ref(false);
+const tableData = ref([]);
+const columnList = ref([]);
+const tableLoading = ref(false);
+const sortKeys = reactive([
+  'Expiration', 'ModifyTime', 'LastLoginTime', 'ActiveTime',
+  'IndexNum', 'ChartNum', 'LoginNum', 'LastLoginDuration',
+]);
+const SortParam = ref('');
+const SortType = ref('');
+const applyInfo = reactive({});
+const currentPage = ref(1);
+const pageSize = ref(10);
+const total = ref(1);
+const isApplyApprovalDialogShow = ref(false);
+const isAddApplyHintShow = ref(false);
+const showDetailDialogShow = ref(false);
+const isIndeterminate = ref(false);
+const isCheckAll = ref(false);
+const isSelectAll = ref(false);
+const selectList = ref([]);
+const choiceIdList = ref([]);
+const tableDataIds = ref([]);
+const isMoveShow = ref(false);
+const moveInfo = reactive({
+  type: 1, // 1 移动 2 批量移动
+  salesArr: [], // 销售列表
+  selectArr: [], // 已选择的id
+});
+
+// 计算属性
+const Role = computed(() => localStorage.getItem('Role'));
+const selectedTotal = computed(() => {
+  if (isSelectAll.value) {
+    return total.value - selectList.value.length;
+  } else {
+    return selectList.value.length;
+  }
+});
+
+// 监听器
+watch('route.path', (newVal) => {
+  currentPath.value = newVal;
+  currentPage.value = 1;
+  SortParam.value = '';
+  SortType.value = '';
+  approvalState.value = 2;
+  searchText.value = '';
+  getTableData();
+});
+watch('listType', (val) => {
+  currentPage.value = 1;
+  SortParam.value = '';
+  SortType.value = '';
+  approvalState.value = 2;
+  searchText.value = '';
+  getTableData();
+});
+
+// 方法
+const getSalesArr = async () => {
+  const res = await customInterence.getSale();
+  if (res.Ret === 200) {
+    moveInfo.salesArr = res.Data.List || [];
+  }
+};
+
+const getTableData = async (type) => {
+  tableLoading.value = true;
+  let interenceName = 'getETATrialList';
+  if (currentPath.value === '/etaTrialList') {
+    canEdit.value = false;
+    columnList.value = etaTrialColumn;
+    interenceName = 'getETATrialList';
+  } else if (currentPath.value === '/etaApprovalList') {
+    canEdit.value = true;
+    if (listType.value !== 'all') {
+      columnList.value = approvedList;
+      interenceName = 'getApprovalList';
+    }
+  }
+  columnList.value = etaTrialColumn
+  console.log(etaTrialColumn);
+  
+  const res = await etaTrialInterence[interenceName]({
+    PageSize: pageSize.value,
+    CurrentIndex: currentPage.value,
+    KeyWord: searchText.value,
+    SortParam: SortParam.value,
+    SortType: SortType.value,
+    ListParam: approvalState.value,
+    IsOnlyMe: onlyMine.value,
+  });
+  if (res.Ret !== 200) return;
+  const { List, Paging, ApprovalNum } = res.Data;
+  tableData.value = List || [];
+  total.value = Paging.Totals;
+  approvalNum.value = ApprovalNum || 0;
+  tableLoading.value = false;
+  if (tableData.value.length > 0) {
+    tableDataIds.value = tableData.value.map(it => it.EtaTrialId);
+  } else {
+    tableDataIds.value = [];
+  }
+  if (type === 'search') {
+    selectList.value = [];
+    listCheckAllChange(false);
+  } else {
+    adjustSelection();
+  }
+};
+
+
+const sortChangeHandle = ({ prop, order }) => {
+  SortParam.value = prop;
+  SortType.value = order === 'ascending' ? 'asc' : 'desc';
+  currentPage.value = 1;
+  getTableData();
+};
+
+const searchHandle = () => {
+  currentPage.value = 1;
+  getTableData();
+};
+
+const selectHandle = (change) => {
+  currentPage.value = 1;
+  approvalState.value = change;
+  getTableData();
+};
+
+const onlyMineChange = () => {
+  currentPage.value = 1;
+  getTableData();
+};
+
+const changePath = (path) => {
+  if (currentPath.value === path) return;
+  currentPath.value = path;
+  router.push(path); // 确保 router 已被正确导入
+};
+
+const toQuestionnaireSurvey = () => {
+  router.push('/questionnaireSurvey'); // 确保 router 已被正确导入
+};
+
+const handleCurrentChange = (pageNo) => {
+  currentPage.value = pageNo;
+  getTableData();
+};
+
+const adjustSelection = () => {
+  if (!isSelectAll.value) {
+    tableData.value.forEach(it => {
+      if (selectList.value.includes(it.EtaTrialId)) {
+        // 假设这里有一个方法 toggleRowSelection 来切换行的选中状态
+        // toggleRowSelection(it, true);
+      }
+    });
+  } else {
+    tableData.value.forEach(it => {
+      if (!selectList.value.includes(it.EtaTrialId)) {
+        // toggleRowSelection(it, true);
+      }
+    });
+  }
+};
+
+const listCheckAllChange = (value) => {
+  selectList.value = [];
+  isSelectAll.value = value;
+  // 假设这里有一个方法来清除所有行的选中状态
+  // clearSelection();
+  if (value) {
+    // 假设这里有一个方法来选中所有行
+    // toggleAllSelection();
+  }
+};
+
+const selectionChange = (selection) => {
+  setTimeout(() => {
+    const duplicateArr = Array.from(new Set(selectList.value));
+    if ((duplicateArr.length === total.value && !isSelectAll.value) || (duplicateArr.length === 0 && isSelectAll.value)) {
+      isCheckAll.value = true;
+      isIndeterminate.value = false;
+    } else if ((duplicateArr.length === 0 && !isSelectAll.value) || (duplicateArr.length === total.value && isSelectAll.value)) {
+      isCheckAll.value = false;
+      isIndeterminate.value = false;
+    } else {
+      isCheckAll.value = false;
+      isIndeterminate.value = true;
+    }
+  }, 1);
+};
+
+const selectHandles = (selection, row) => {
+  let check = false;
+  if (selection.some(it => it.EtaTrialId === row.EtaTrialId)) {
+    if (isSelectAll.value) {
+      check = false;
+    } else {
+      check = true;
+    }
+  } else {
+    if (isSelectAll.value) {
+      check = true;
+    } else {
+      check = false;
+    }
+  }
+  if (check) {
+    selectList.value.push(row.EtaTrialId);
+  } else {
+    selectList.value = selectList.value.filter(it => it !== row.EtaTrialId);
+  }
+};
+
+const selectAllHandle = (selection) => {
+  let check = false;
+  if (selection && selection.length > 0) {
+    if (isSelectAll.value) {
+      check = false;
+    } else {
+      check = true;
+    }
+  } else {
+    if (isSelectAll.value) {
+      check = true;
+    } else {
+      check = false;
+    }
+  }
+  if (check) {
+    selectList.value = [...selectList.value, ...tableDataIds.value];
+  } else {
+    selectList.value = selectList.value.filter(it => !tableDataIds.value.includes(it));
+  }
+};
+
+const getApplyInfo = (type, data) => {
+  const temp = { applyType: 1, applyData: [] };
+  temp.applyType = data.ApplyMethod || 2;
+  if ((type === 'apply' || type === 'withdraw' || type === 'approve') && data.ApplyMethod === 2) {
+    temp.applyType = 0;
+  }
+  if (type === 'active') {
+    temp.applyType = 0;
+  }
+  temp.applyData = [data];
+  applyInfo = temp;
+};
+
+const handleOperate = async (type, data) => {
+  getApplyInfo(type, data);
+  if (type === 'approve') {
+    isApplyApprovalDialogShow.value = true;
+  } else if (type === 'active') {
+    isAddApplyHintShow.value = true;
+  } else if (type === 'apply') {
+    const { ApplyMethod } = data;
+    if (ApplyMethod === 1) {
+      sessionStorage.setItem('applyInfo', JSON.stringify(applyInfo));
+      router.push('/etaAddApproval'); // 确保 router 已被正确导入
+    } else {
+      isAddApplyHintShow.value = true;
+    }
+  } else if (type === 'withdraw') {
+    const res = await etaTrialInterence.withdrawApproval({ Mobile: data.Mobile });
+    if (res.Ret !== 200) return;
+    const confirmResult = await confirm('', '撤回成功', {
+      confirmButtonText: '重新申请',
+      cancelButtonText: '取消',
+      cancelButtonClass: "btn-custom-cancel",
+      type: 'success',
+      center: true,
+    });
+    if (confirmResult) {
+      const { ApplyMethod } = data;
+      if (ApplyMethod === 1) {
+        sessionStorage.setItem('applyInfo', JSON.stringify(applyInfo));
+        router.push('/etaAddApproval'); // 确保 router 已被正确导入
+      } else {
+        isAddApplyHintShow.value = true;
+      }
+    } else {
+      getTableData();
+    }
+  } else if (type === 'checkReplay') {
+    await confirm(data.ApprovalRemark || '', '驳回理由', {
+      confirmButtonText: '知道了',
+      showCancelButton: false,
+    });
+  } else if (type === 'delete') {
+    const confirmResult = await confirm('此操作将永久删除该数据, 是否继续?', '提示', {
+      confirmButtonText: '确认',
+      cancelButtonText: '取消',
+      type: 'warning',
+    });
+    if (confirmResult) {
+      const res = await etaTrialInterence.deleteApproval({ ApprovalId: data.ApprovalId });
+      if (res.Ret !== 200) return;
+      getTableData();
+      message.success('删除成功'); // 确保 message 已被正确导入
+    }
+  } else if (type === 'showDetail') {
+    showDetailDialogShow.value = true;
+  }
+};
+
+const closeDialog = () => {
+  isAddApplyHintShow.value = false;
+  getTableData();
+};
+
+const moveConfirm = (data) => {
+  const { type, value, selectArr } = data;
+  const currentSellerId = parseInt(value[value.length - 1]);
+  const params = {
+    currentSellerId,
+    EtaTrialIdList: selectArr,
+    IsCheckAll: type === 1 ? false : isSelectAll.value,
+    CurrentSellerName: findElementByAdminId(moveInfo.salesArr, currentSellerId).RealName,
+  };
+  etaTrialInterence.accountTransfer(params).then(res => {
+    if (res.Ret !== 200) return;
+    message.success('移动成功'); // 确保 message 已被正确导入
+    getTableData();
+    isMoveShow.value = false;
+  });
+};
+
+const findElementByAdminId = (arr, adminId) => {
+  adminId = adminId + '';
+  for (const element of arr) {
+    if (element.AdminId === adminId) {
+      return element;
+    }
+    if (element.ChildrenList && element.ChildrenList.length > 0) {
+      const found = findElementByAdminId(element.ChildrenList, adminId);
+      if (found) {
+        return found;
+      }
+    }
+  }
+  return null;
+};
+
+const closeMove = () => {
+  isMoveShow.value = false;
+};
+
+const Move = (row) => {
+  moveInfo.type = 1;
+  moveInfo.selectArr = [row.EtaTrialId];
+  isMoveShow.value = true;
+};
+
+const batchMove = () => {
+  if (selectList.value.length === 0) {
+    message.warning('请至少选择一个客户'); // 确保 message 已被正确导入
+    return;
+  }
+  moveInfo.type = 2;
+  moveInfo.selectArr = selectList.value;
+  isMoveShow.value = true;
+};
+
+const batchOperate = async () => {
+  if (getMobileList(tableData.value, selectList.value).length === 0) {
+    message.warning('请至少选择一个客户'); // 确保 message 已被正确导入
+    return;
+  }
+  const res = await etaTrialInterence.applyEnable({
+    MobileList: getMobileList(tableData.value, selectList.value),
+    IsCheckAll: isSelectAll.value,
+  });
+  if (res.Ret !== 200) return;
+  getTableData();
+  message.success('启用成功'); // 确保 message 已被正确导入
+};
+
+const getMobileList = (array1, array2) => {
+  return array1.filter(element => array2.includes(element.EtaTrialId)).map(element => element.Mobile);
+};
+
+// 生命周期钩子
+onMounted(() => {
+  currentPath.value = route.path;
+  getTableData();
+  getSalesArr();
+});
+</script>
+<style lang="scss">
+.btn-custom-cancel{ 
+  float: right;
+  margin-left: -100px;
+  margin-right: 110px;
+}
+</style>
+<style scoped lang="scss">
+.eta-trial-list{
+  padding:30px;
+  background-color: #fff;
+  border-radius: 4px;
+  .table-select{
+    display: flex;
+    justify-content: space-between;
+    .btn-list{
+      .approval-hint{
+        margin-left: 15px;
+        border-radius: 4px;
+        padding:5px 12px;
+        background-color: #FEF0F0;
+        color: #F56C6C;
+        position: relative;
+        &::before{
+          content: '';
+          position:absolute;
+          width:0;
+          height:0;
+          left:-12px;
+          top:calc(50% - 6px);
+          border: 6px solid transparent;
+          border-right: 6px solid #FEF0F0;
+        }
+      }
+      .tips {
+        margin: 10px 25px;
+        font-family: Arial;
+        font-size: 15px;
+        font-weight: 400;
+        line-height: 17.25px;
+        text-align: center;
+        color: rgba(153, 153, 153, 1);
+      }
+      .right-header {
+        margin-top: 40px;
+      }
+    }
+    .search-wrap{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+  }
+  .table-wrap{
+    margin-top:30px;
+  }
+
+  .color-hint{
+    color: red;
+  }
+  .apply-detail{
+      display: flex;
+      flex-direction: column;
+      gap:20px;
+      p{
+          font-size: 16px;
+          margin-left: 20px;
+      }
+      .button{
+          text-align: center;
+          padding-bottom: 25px;
+      }
+  }
+}
+</style>

+ 2 - 2
vite.config.js

@@ -93,8 +93,8 @@ export default defineConfig(({ mode }) => {
       proxy:{
         '/v1': {
           // target: 'http://192.168.20.10:8912/v1',
-          target: 'http://8.136.199.33:8900/v1',
-          // target: 'http://8.136.199.33:7777/adminapi/',
+          // target: 'http://8.136.199.33:8900/v1',
+          target: 'http://8.136.199.33:7777/adminapi/',
           changeOrigin: true,
           rewrite: (path) => path.replace(/^\/v1/, ''),
         }