Ver Fonte

ai角色账号管理

kyoyue há 7 meses atrás
pai
commit
3e72fbb1a6

+ 1 - 1
.env

@@ -1,3 +1,3 @@
 # spa-title
-VITE_GLOB_APP_TITLE = 冠客微信管理系统
+VITE_GLOB_APP_TITLE = 
 

+ 1 - 1
.vscode/settings.json

@@ -63,7 +63,7 @@
     "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
   "[typescript]": {
-    "editor.defaultFormatter": "esbenp.prettier-vscode"
+    "editor.defaultFormatter": "vscode.typescript-language-features"
   },
   "[typescriptreact]": {
     "editor.defaultFormatter": "esbenp.prettier-vscode"

+ 1 - 1
index.html

@@ -9,7 +9,7 @@
       content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
     />
     <title><%= VITE_GLOB_APP_TITLE %></title>
-    <link rel="icon" href="/favicon.ico" />
+    <link rel="icon" href="./src/assets/images/gooki.ico" />
   </head>
   <body>
     <div id="app">

+ 2 - 0
src/api/wechat/model/wxModel.ts

@@ -5,6 +5,8 @@ import { BaseListResp } from '@/api/model/baseModel';
  */
 export interface WxInfo {
   id?: number;
+  agentId?: number;
+  agentInfo?: object;
   createdAt?: number;
   updatedAt?: number;
   status?: number;

+ 8 - 0
src/api/wechat/wx.ts

@@ -9,6 +9,7 @@ enum Api {
   GetWxList = '/wechat-api/wx/list',
   DeleteWx = '/wechat-api/wx/delete',
   GetWxById = '/wechat-api/wx',
+  GetSysInfo = '/wechat-api/user/info',
 }
 
 /**
@@ -72,3 +73,10 @@ export const getWxById = (params: BaseIDReq, mode: ErrorMessageMode = 'notice')
     },
   );
 };
+
+/**
+ *  @description: 获取系统信息
+ */
+export const getSysInfo = () => {
+  return defHttp.get<BaseDataResp<BaseIDsReq>>({ url: Api.GetSysInfo });
+};

BIN
src/assets/images/emoj.png


BIN
src/assets/images/file.png


BIN
src/assets/images/link.png


BIN
src/assets/images/text.png


+ 11 - 5
src/components/Application/src/AppLogo.vue

@@ -16,14 +16,15 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { computed, unref } from 'vue';
+  import { computed, unref ,onMounted ,ref} from 'vue';
   import { useGlobSetting } from '@/hooks/setting';
   import { useGo } from '@/hooks/web/usePage';
   import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
   import { useDesign } from '@/hooks/web/useDesign';
   import { PageEnum } from '@/enums/pageEnum';
   import { useUserStore } from '@/store/modules/user';
-
+  import {getSysInfo} from '@/api/wechat/wx'
+  
   const props = defineProps({
     /**
      * The theme of the current parent component
@@ -38,13 +39,18 @@
      */
     alwaysShowTitle: { type: Boolean },
   });
-
+  const title = ref('');
+  onMounted(async () => {
+     let res = await getSysInfo()
+     title.value = res.data.departmentName
+     document.title = title.value;
+  }) 
   const { prefixCls } = useDesign('app-logo');
   const { getCollapsedShowTitle } = useMenuSetting();
   const userStore = useUserStore();
-  const { title } = useGlobSetting();
+  // const { title } = useGlobSetting();
+  
   const go = useGo();
-
   const getAppLogoClass = computed(() => [
     prefixCls,
     props.theme,

+ 2 - 2
src/components/SimpleMenu/src/SimpleMenu.vue

@@ -7,13 +7,13 @@
     :activeSubMenuNames="activeSubMenuNames"
     @select="handleSelect"
   >
-  <div class="switch" >
+  <!-- <div class="switch" v-show="!collapse">
     <div class="switch__text">
       <span class="switch__text__span" :style="{ opacity: isScrm == 'SCRM' ? 0 : 1 }" @click="toggleSwitch('SCRM')">SCRM</span>
       <span class="switch__text__span" :style="{ opacity: isScrm == 'CHAT' ? 0 : 1, width: '92px' }" @click="toggleSwitch('CHAT')">聚合聊天</span>
       <div class="switch__slider" :style="{ left: isScrm == 'SCRM' ? '6px' : '92px' }">{{ isScrm == 'SCRM' ? 'SCRM' : '聚合聊天' }}</div>
     </div>
-  </div>
+  </div> -->
     <template v-for="item in items" :key="item.path">
       <SimpleSubMenu
         :item="item"

+ 4 - 2
src/locales/lang/zh-CN/sys.ts

@@ -1,3 +1,4 @@
+
 export default {
   api: {
     operationFailed: '操作失败',
@@ -66,7 +67,7 @@ export default {
     signUpFormTitle: '注册',
     forgetFormTitle: '重置密码',
 
-    signInTitle: '冠客微信管理系统',
+    signInTitle: '',
     signInDesc: '商机无限',
     policy: '我同意隐私政策',
     scanSign: `扫码后点击"确认",即可完成登录`,
@@ -224,7 +225,7 @@ export default {
     navigation: '快捷导航',
     info: '系统信息',
     // notification
-    welcome: '欢迎使用 冠客微信管理系统',
+    welcome: '欢迎使用 ',
   },
   dictionary: {
     // noun
@@ -335,4 +336,5 @@ export default {
     editTaskLog: '编辑任务日志',
     taskLogList: '任务日志列表',
   },
+  
 };

+ 8 - 2
src/views/dashboard/workbench/components/WorkbenchHeader.vue

@@ -2,7 +2,7 @@
   <div class="lg:flex">
     <Avatar :src="userinfo.avatar || headerImg" :size="72" class="!mx-auto !block" />
     <div class="md:ml-6 flex flex-col justify-center md:mt-0 mt-2">
-      <h1 class="md:text-lg text-md bench-header">{{ t('sys.sys.welcome') }}</h1>
+      <h1 class="md:text-lg text-md bench-header">{{ '欢迎使用' +  title}}</h1>
       <!-- <span class="text-secondary"> 今日晴,20℃ - 32℃! </span> -->
     </div>
     <div class="flex flex-1 justify-end md:mt-0 mt-4">
@@ -23,15 +23,21 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { computed } from 'vue';
+  import { computed ,onMounted,ref} from 'vue';
   import { Avatar } from 'ant-design-vue';
   import { useUserStore } from '@/store/modules/user';
   import headerImg from '@/assets/images/header.jpg';
   import { useI18n } from 'vue-i18n';
+  import {getSysInfo} from '@/api/wechat/wx'
 
   const { t } = useI18n();
   const userStore = useUserStore();
   const userinfo = computed(() => userStore.getUserInfo);
+  const title = ref('')
+  onMounted(async () => {
+     let res = await getSysInfo()
+     title.value = res.data.departmentName
+  }) 
 </script>
 
 <style lang="less" scoped>

+ 2 - 1
src/views/dashboard/workbench/components/data.ts

@@ -49,8 +49,9 @@ export const navItems: NavItem[] = [
   //   redirect: '/file',
   // },
 ];
+const title = document.title;
 
 export const systemInfoData = [
-  ['sys.sys.Name', '冠客微信管理系统'],
+  ['sys.sys.Name', title],
   ['sys.sys.version', 'V 0.0.1'],
 ];

+ 2 - 33
src/views/sys/role/role.data.ts

@@ -84,10 +84,10 @@ export const formSchema: FormSchema[] = [
     required: true,
     component: 'Input',
     componentProps: {
-      maxlength: 20,
+      maxlength: 30,
       showCount: true,
     },
-    rules: [{ max: 20 }],
+    rules: [{ max: 30 }],
   },
   {
     field: 'sort',
@@ -128,37 +128,6 @@ export const formSchema: FormSchema[] = [
     component: 'InputTextArea',
     rules: [{ max: 200 }],
   },
-  {
-    label: '角色设定',
-    field: 'roleSetting',
-    component: 'InputTextArea',
-    required: true,
-    componentProps: {
-      maxlength: 1000,
-      showCount: true,
-    },
-    rules: [{ max: 1000 }],
-  },
-  {
-    label: '背景介绍',
-    field: 'bgIntroduction',
-    component: 'InputTextArea',
-    componentProps: {
-      maxlength: 1000,
-      showCount: true,
-    },
-    rules: [{ max: 1000 }],
-  },
-  {
-    label: '对话案例',
-    field: 'dialogueCase',
-    component: 'InputTextArea',
-    componentProps: {
-      maxlength: 5000,
-      showCount: true,
-    },
-    rules: [{ max: 5000 }],
-  },
 ];
 
 /**

+ 1 - 0
src/views/wechat/agent/AgentDrawer.vue

@@ -54,6 +54,7 @@
 
       async function handleSubmit() {
         const values = await validate();
+        console.log(values,'values')
         setDrawerProps({ confirmLoading: true });
         values['id'] = unref(isUpdate) ? Number(values['id']) : 0;
         let result = unref(isUpdate) ? await updateAgent(values) : await createAgent(values);

+ 60 - 42
src/views/wechat/agent/agent.data.ts

@@ -28,33 +28,33 @@ export const columns: BasicColumn[] = [
     dataIndex: 'examples',
     width: 100,
   },
-  {
-    title: t('common.status'),
-    dataIndex: 'status',
-    width: 50,
-    customRender: ({ record }) => {
-      if (!Reflect.has(record, 'pendingStatus')) {
-        record.pendingStatus = false;
-      }
-      return h(Switch, {
-        checked: record.status === 1,
-        checkedChildren: t('common.on'),
-        unCheckedChildren: t('common.off'),
-        loading: record.pendingStatus,
-        onChange(checked, _) {
-          record.pendingStatus = true;
-          const newStatus = checked ? 1 : 2;
-          updateAgent({ id: record.id, status: newStatus })
-            .then(() => {
-              record.status = newStatus;
-            })
-            .finally(() => {
-              record.pendingStatus = false;
-            });
-        },
-      });
-    },
-  },
+  // {
+  //   title: t('common.status'),
+  //   dataIndex: 'status',
+  //   width: 50,
+  //   customRender: ({ record }) => {
+  //     if (!Reflect.has(record, 'pendingStatus')) {
+  //       record.pendingStatus = false;
+  //     }
+  //     return h(Switch, {
+  //       checked: record.status === 1,
+  //       checkedChildren: t('common.on'),
+  //       unCheckedChildren: t('common.off'),
+  //       loading: record.pendingStatus,
+  //       onChange(checked, _) {
+  //         record.pendingStatus = true;
+  //         const newStatus = checked ? 1 : 2;
+  //         updateAgent({ id: record.id, status: newStatus })
+  //           .then(() => {
+  //             record.status = newStatus;
+  //           })
+  //           .finally(() => {
+  //             record.pendingStatus = false;
+  //           });
+  //       },
+  //     });
+  //   },
+  // },
   {
     title: t('common.createTime'),
     dataIndex: 'createdAt',
@@ -98,35 +98,53 @@ export const formSchema: FormSchema[] = [
     label: t('wechat.agent.name'),
     component: 'Input',
     required: true,
+    componentProps: {
+      maxlength: 20,
+      showCount: true,
+    },
+    rules: [{ max: 20 }],
   },
   {
     field: 'role',
     label: t('wechat.agent.role'),
-    component: 'Input',
+    component: 'InputTextArea',
     required: true,
+    componentProps: {
+      maxlength: 1000,
+      showCount: true,
+    },
+    rules: [{ max: 1000 }],
   },
   {
     field: 'background',
     label: t('wechat.agent.background'),
-    component: 'Input',
-    required: true,
+    component: 'InputTextArea',
+    componentProps: {
+      maxlength: 1000,
+      showCount: true,
+    },
+    rules: [{ max: 1000 }],
   },
   {
     field: 'examples',
     label: t('wechat.agent.examples'),
-    component: 'Input',
-    required: true,
-  },
-  {
-    field: 'status',
-    label: t('wechat.agent.status'),
-    component: 'RadioButtonGroup',
-    defaultValue: 1,
+    component: 'InputTextArea',
     componentProps: {
-      options: [
-        { label: t('common.on'), value: 1 },
-        { label: t('common.off'), value: 2 },
-      ],
+      maxlength: 5000,
+      showCount: true,
     },
+    rules: [{ max: 5000 }],
   },
+  // {
+  //   field: 'status',
+  //   label: t('wechat.agent.status'),
+  //   component: 'RadioButtonGroup',
+  //   defaultValue: 1,
+  //   componentProps: {
+  //     options: [
+  //       { label: t('common.on'), value: 1 },
+  //       { label: t('common.off'), value: 2 },
+  //     ],
+  //   },
+  // },
 ];

+ 99 - 71
src/views/wechat/sop_task/perform_tasks/index.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="container">
-    <a-table :columns="columns" :dataSource="data" :pagination="pagination" class="table-style">
+    <a-table
+      :columns="columns"
+      :loading="loading.spinning"
+      :dataSource="data"
+      :pagination="pagination"
+      class="table-style"
+    >
       <!-- 自定义操作列 -->
       <template #action="{ record }">
         <a @click="viewRecord(record)">发送记录</a>
@@ -10,81 +16,103 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, reactive ,onMounted} from 'vue';
-import { Table, Pagination } from 'ant-design-vue';
-import { useRoute ,useRouter} from 'vue-router';
-import { PageEnum } from '@/enums/pageEnum';
-import {getSopTaskRecordList} from '@/api/wechat/sopTask'
-export default defineComponent({
-  name: 'PerformTasks',
-  components: {
-    'a-table': Table,
-    'a-pagination': Pagination,
-  },
-  setup() {
-    const data = reactive([
-    ]);
-    const route = useRoute();
-    const router = useRouter();
-    const columns = reactive([
-      { title: '序号', dataIndex: 'index', key: 'index' },
-      { title: 'SOP任务节点', dataIndex: 'name', key: 'name' },
-      // { title: '日期', dataIndex: 'date', key: 'date' },
-      { title: '成功数', dataIndex: 'successCount', key: 'successCount' },
-      { title: '失败数', dataIndex: 'failureCount', key: 'failureCount' },
-      { title: '成功率', dataIndex: 'successRate', key: 'successRate' ,customRender: ({ text }) => `${text}%`,},
-      { title: '操作', key: 'action', slots: { customRender: 'action' }},
-    ]);
-
-    const pagination = reactive({
-      total: 0,
-      pageSize: 10,
-      current: 1,
-      showTotal: (total) => `共 ${total} 条`,
-    });
+  import { defineComponent, reactive, onMounted } from 'vue';
+  import { Table, Pagination } from 'ant-design-vue';
+  import { useRoute, useRouter } from 'vue-router';
+  import { PageEnum } from '@/enums/pageEnum';
+  import { getSopTaskRecordList } from '@/api/wechat/sopTask';
+  export default defineComponent({
+    name: 'PerformTasks',
+    components: {
+      'a-table': Table,
+      'a-pagination': Pagination,
+    },
+    setup() {
+      const data = reactive([]);
+      const route = useRoute();
+      const router = useRouter();
+      const loading = reactive({
+        spinning: true,
+      });
+      const columns = reactive([
+        { title: '序号', dataIndex: 'index', key: 'index' },
+        {
+          title: '来源类型',
+          dataIndex: 'sourceType',
+          key: 'sourceType',
+          customRender: ({ record }) => {
+            return record.sourceType == 3 ? '阶段' : '节点';
+          },
+        },
+        { title: 'SOP任务节点', dataIndex: 'name', key: 'name' },
+        // { title: '日期', dataIndex: 'date', key: 'date' },
+        { title: '总数', dataIndex: 'totalCount', key: 'totalCount' },
+        { title: '成功数', dataIndex: 'successCount', key: 'successCount' },
+        { title: '失败数', dataIndex: 'failureCount', key: 'failureCount' },
+        {
+          title: '成功率',
+          dataIndex: 'successRate',
+          key: 'successRate',
+          customRender: ({ text }) => `${text}%`,
+        },
+        { title: '操作', key: 'action', slots: { customRender: 'action' } },
+      ]);
 
-    onMounted(async () => {
-      const task_id = route.query.task_id;
-      let res = await getSopTaskRecordList({ id: Number(task_id) });
-      if (res && Array.isArray(res.data)) {
-        res.data.forEach((item, index) => {
-          item.index = index + 1;  // 为每条记录添加序号
-        });
-        data.splice(0, data.length, ...res.data);  // 更新 data
-        pagination.total = res.data.length;
-      }
-    });
+      const pagination = reactive({
+        total: 0,
+        pageSize: 10,
+        current: 1,
+        showTotal: (total) => `共 ${total} 条`,
+      });
 
-    const viewRecord = (record) => {
-      console.log('查看发送记录', record);
-      router.push({
-        path: PageEnum.SEND_TASKS,
-        query: { sourceId: record.sourceId, sourceType: record.sourceType}
+      onMounted(async () => {
+        const task_id = route.query.task_id;
+        try {
+          let res = await getSopTaskRecordList({ id: Number(task_id) });
+          if (res && Array.isArray(res.data)) {
+            res.data.forEach((item, index) => {
+              item.index = index + 1; // 为每条记录添加序号
+            });
+            data.splice(0, data.length, ...res.data); // 更新 data
+            pagination.total = res.data.length;
+          }
+        } catch (error) {
+          console.error('数据加载失败', error);
+        } finally {
+          loading.spinning = false; // 数据加载完成后关闭加载指示器
+        }
       });
-    };
 
-    return {
-      data,
-      columns,
-      pagination,
-      viewRecord,
-    };
-  },
-});
+      const viewRecord = (record) => {
+        router.push({
+          path: PageEnum.SEND_TASKS,
+          query: { sourceId: record.sourceId, sourceType: record.sourceType },
+        });
+      };
+
+      return {
+        data,
+        columns,
+        pagination,
+        viewRecord,
+        loading,
+      };
+    },
+  });
 </script>
 
 <style scoped>
-.container{
-  background-color: #fff;
-  margin: 20px;
-  border-radius: 4px;
-  height: calc(100vh - 40px);
-  width: calc(100% - 40px);
-}
-.ant-table-cell {
-  text-align: center;
-}
-.table-style{
-  padding: 16px;
-}
+  .container {
+    background-color: #fff;
+    margin: 20px;
+    border-radius: 4px;
+    height: calc(100vh - 40px);
+    width: calc(100% - 40px);
+  }
+  .ant-table-cell {
+    text-align: center;
+  }
+  .table-style {
+    padding: 16px;
+  }
 </style>

+ 146 - 107
src/views/wechat/sop_task/send_tasks/index.vue

@@ -6,23 +6,23 @@
       </a-form-item>
       <a-form-item label="社交账号">
         <a-select v-model:value="filters.socialAccount" placeholder="请选择" class="select-style">
-          <a-select-option value="account1">账号1</a-select-option>
-          <a-select-option value="account2">账号2</a-select-option>
+          <a-select-option value="1">好友</a-select-option>
+          <a-select-option value="2">群组</a-select-option>
         </a-select>
       </a-form-item>
       <a-form-item label="类型">
         <a-select v-model:value="filters.type" placeholder="请选择" class="select-style">
-          <a-select-option value="personal">个人微信</a-select-option>
-          <a-select-option value="enterprise">企业微信</a-select-option>
+          <a-select-option value="1">好友</a-select-option>
+          <a-select-option value="2">群组</a-select-option>
         </a-select>
       </a-form-item>
-      <a-form-item label="执行结果">
+      <!-- <a-form-item label="执行结果">
         <a-select v-model:value="filters.result" placeholder="请选择" class="select-style">
           <a-select-option value="notSend">未发送</a-select-option>
           <a-select-option value="success">成功</a-select-option>
           <a-select-option value="failure">失败</a-select-option>
         </a-select>
-      </a-form-item>
+      </a-form-item> -->
       <a-form-item>
         <a-button type="primary" @click="onSearch">查询</a-button>
       </a-form-item>
@@ -30,7 +30,13 @@
         <a-button @click="onReset">重置</a-button>
       </a-form-item>
     </a-form>
-    <a-table :columns="columns" :dataSource="data" :pagination="pagination" class="table-style">
+    <a-table
+      :columns="columns"
+      :dataSource="data"
+      :pagination="pagination"
+      :loading="loading.spinning"
+      class="table-style"
+    >
       <template #action="{ record }">
         <a @click="viewRecord(record)">发送记录</a>
       </template>
@@ -39,117 +45,150 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, reactive,onMounted } from 'vue';
-import { Form, Input, Select, Button, Table, Pagination } from 'ant-design-vue';
-import { useRoute } from 'vue-router';
-import { getSopTaskRecordMsg } from '@/api/wechat/sopTask'
-import dayjs from 'dayjs';
+  import { defineComponent, reactive, onMounted } from 'vue';
+  import { Form, Input, Select, Button, Table, Pagination } from 'ant-design-vue';
+  import { useRoute } from 'vue-router';
+  import { getSopTaskRecordMsg } from '@/api/wechat/sopTask';
+  import dayjs from 'dayjs';
 
-export default defineComponent({
-  name: 'SendTasks',
-  components: {
-    'a-form': Form,
-    'a-form-item': Form.Item,
-    'a-input': Input,
-    'a-select': Select,
-    'a-select-option': Select.Option,
-    'a-button': Button,
-    'a-table': Table,
-    'a-pagination': Pagination,
-  },
-  setup() {
-    const filters = reactive({
-      customer: '',
-      socialAccount: '',
-      type: '',
-      result: '',
-    });
-    const route = useRoute();
-    const data = reactive([
-    ]);
+  export default defineComponent({
+    name: 'SendTasks',
+    components: {
+      'a-form': Form,
+      'a-form-item': Form.Item,
+      'a-input': Input,
+      'a-select': Select,
+      'a-select-option': Select.Option,
+      'a-button': Button,
+      'a-table': Table,
+      'a-pagination': Pagination,
+    },
+    setup() {
+      const filters = reactive({
+        customer: '',
+        socialAccount: '',
+        type: '',
+        result: '',
+      });
+      const route = useRoute();
+      const data = reactive([]);
+      const loading = reactive({
+        spinning: true,
+      });
 
-    const columns = reactive([
-      { title: '序号', dataIndex: 'index', key: 'index' },
-      { title: '社交账号', dataIndex: 'botWxid', key: 'botWxid' },
-      { title: '客户', dataIndex: 'contactWxid', key: 'contactWxid' },
-      { title: 'SOP任务节点名称', dataIndex: 'content', key: 'content' },
-      { title: '执行状态', dataIndex: 'result', key: 'result' },
-      { title: '异常原因', dataIndex: 'errorDetail', key: 'errorDetail' },
-      { title: '最新执行时间', dataIndex: 'sendTime', key: 'sendTime', customRender: ({ text }) => dayjs(text).format('YY-MM-DD HH:mm:ss')},
-      // { title: '操作', key: 'action', slots: { customRender: 'action' } },
-    ]);
+      const columns = reactive([
+        { title: '序号', dataIndex: 'index', key: 'index' },
+        { title: '微信ID', dataIndex: 'botWxid', key: 'botWxid' },
+        { title: '联系人微信ID', dataIndex: 'contactWxid', key: 'contactWxid' },
+        {
+          title: '联系人类型',
+          dataIndex: 'contactType',
+          key: 'contactType',
+          customRender: ({ record }) => {
+            return record.contactType == 1 ? '好友' : '群组';
+          },
+        },
+        { title: '内容', dataIndex: 'content', key: 'content' },
+        {
+          title: '内容类型',
+          dataIndex: 'contentType',
+          key: 'contentType',
+          customRender: ({ record }) => {
+            return record.contentType == 1 ? '文本' : '文件';
+          },
+        },
+        { title: '错误信息', dataIndex: 'errorDetail', key: 'errorDetail' },
+        {
+          title: '发送时间',
+          dataIndex: 'sendTime',
+          key: 'sendTime',
+          customRender: ({ text }) => dayjs(text).format('YY-MM-DD HH:mm:ss'),
+        },
+        // { title: '操作', key: 'action', slots: { customRender: 'action' } },
+      ]);
 
-    onMounted(async () => {
-      const sourceId = route.query.sourceId;
-      const sourceType = route.query.sourceType;
-      let res = await getSopTaskRecordMsg({ sourceId: Number(sourceId) ,sourceType: Number(sourceType),page:1,pageSize:50});
-      console.log(res)
-      if (res && Array.isArray(res.data.data)) {
-        res.data.data.forEach((item, index) => {
-          item.index = index + 1;  // 为每条记录添加序号
+      onMounted(async () => {
+        const sourceId = route.query.sourceId;
+        const sourceType = route.query.sourceType;
+        try {
+        const res = await getSopTaskRecordMsg({
+          sourceId: Number(sourceId),
+          sourceType: Number(sourceType),
+          page: 1,
+          pageSize: 50,
         });
-        data.splice(0, data.length, ...res.data.data);  // 更新 data
-        pagination.total = res.data.total;
+        if (res && Array.isArray(res.data.data)) {
+          res.data.data.forEach((item, index) => {
+            item.index = index + 1; // 为每条记录添加序号
+          });
+          data.splice(0, data.length, ...res.data.data); // 更新 data
+          pagination.total = res.data.total;
+        }
+      } catch (error) {
+        console.error('数据加载失败', error);
+      } finally {
+        loading.spinning = false; // 数据加载完成后关闭加载指示器
       }
-    });
+      });
 
-    const pagination = reactive({
-      total: 0,
-      pageSize: 10,
-      current: 1,
-      showTotal: (total) => `共 ${total} 条`,
-    });
+      const pagination = reactive({
+        total: 0,
+        pageSize: 10,
+        current: 1,
+        showTotal: (total) => `共 ${total} 条`,
+      });
 
-    const onSearch = () => {
-      console.log('查询条件', filters);
-      // 在这里添加查询逻辑
-    };
+      const onSearch = () => {
+        console.log('查询条件', filters);
+        // 在这里添加查询逻辑
+      };
 
-    const onReset = () => {
-      filters.customer = '';
-      filters.socialAccount = '';
-      filters.type = '';
-      filters.result = '';
-    };
+      const onReset = () => {
+        filters.customer = '';
+        filters.socialAccount = '';
+        filters.type = '';
+        filters.result = '';
+      };
 
-    const viewRecord = (record) => {
-      console.log('查看发送记录', record);
-      // 在这里添加你的逻辑,比如跳转到发送记录页面或显示模态框
-    };
+      const viewRecord = (record) => {
+        console.log('查看发送记录', record);
+        // 在这里添加你的逻辑,比如跳转到发送记录页面或显示模态框
+      };
 
-    return {
-      filters,
-      data,
-      columns,
-      pagination,
-      onSearch,
-      onReset,
-      viewRecord,
-    };
-  },
-});
+      return {
+        filters,
+        data,
+        columns,
+        pagination,
+        onSearch,
+        onReset,
+        viewRecord,
+        loading,
+      };
+    },
+  });
 </script>
 
 <style scoped>
-.container{
-  background-color: #fff;
-  margin: 20px;
-  border-radius: 4px;
-  height: calc(100vh - 40px);
-  width: calc(100% - 40px);
-}
-.ant-table-cell {
-  text-align: center;
-}
-.table-style{
-  padding: 16px;
-}
-.form-style{
-  /* width: ; */
-  height: 55px;
-  padding: 16px;
-}
-.select-style{
-  width: 180px;
-}
+  .container {
+    background-color: #fff;
+    margin: 20px;
+    border-radius: 4px;
+    height: calc(100vh - 40px);
+    width: calc(100% - 40px);
+  }
+  .ant-table-cell {
+    text-align: center;
+  }
+  .table-style {
+    padding: 16px;
+  }
+  .form-style {
+    /* width: ; */
+    height: 55px;
+    padding: 16px;
+  }
+  .select-style {
+    width: 180px;
+  }
 </style>

+ 136 - 14
src/views/wechat/wechat_main/components/split_wrapper.vue

@@ -8,8 +8,9 @@
         <div class="room-container-header-operate">
           <span class="item-margin">
             <div class="room-operate">
-                {{ '房主' }}<Badge dot status="success" class="badge-right-bottom"></Badge>
-              </div>
+              {{ '房主' }}
+              <Badge dot status="success" class="badge-right-bottom"></Badge>
+            </div>
           </span>
           <span class="item-margin">
             <FileSearchOutlined style="font-size: 20px; color: #666667" />
@@ -21,14 +22,44 @@
               un-checked-children="人工"
             />
           </span>
-          <span class="item-margin" style="margin-right:30px;">
+          <span class="item-margin" style="margin-right: 30px">
             <EllipsisOutlined style="font-size: 20px; color: #333" />
           </span>
         </div>
       </div>
+      <!-- 聊天对话区域 -->
+      <div class="room-container-body">
+        <div v-show="false" class="chat-roomings-tip-box">
+          <span style="color: #307ef2;font-size14px;">当前用户正在被人工接待...</span>
+          <Button class="chat-roomings-tip-btn" size="small">自动回复</Button>
+        </div>
+        <div v-show="false" class="room-container-body-messages">
+          <div class="room-container__loading">
+            加载中...
+            <LoadingOutlined />
+          </div>
+        </div>
+      </div>
     </div>
     <div class="panel bottom-panel">
-      <p>这是下侧面板的内容。</p>
+      <div class="chat-roomings__message">
+        <div class="send-message">
+          <div class="editor">
+            <div class="header">
+              <div class="left-part">
+                <div class="img-emo"></div>
+                <div class="img-file"></div>
+                <div class="img-link"></div>
+                <div class="img-text"></div>
+                <!-- <SmileOutlined />
+                <FolderOutlined />
+                <LayoutOutlined /> -->
+              </div>
+              <div class="right-part"></div>
+            </div>
+          </div>
+        </div>
+      </div>
     </div>
   </div>
 </template>
@@ -36,8 +67,8 @@
 <script lang="ts" setup>
   import { onMounted, ref, reactive } from 'vue';
   import Split from 'split.js';
-  import { Popover, Switch, Badge } from 'ant-design-vue';
-  import { EllipsisOutlined, FileSearchOutlined } from '@ant-design/icons-vue';
+  import { Popover, Switch, Badge, Button } from 'ant-design-vue';
+  import { EllipsisOutlined, FileSearchOutlined, LoadingOutlined ,SmileOutlined,FolderOutlined,LayoutOutlined} from '@ant-design/icons-vue';
 
   const splitContainer = ref(null);
   const state = reactive({
@@ -141,12 +172,103 @@
     font-size: 12px;
   }
   .badge-right-bottom {
-  position: absolute; /* 绝对定位 */
-  bottom: -5px; /* 定位到底部 */
-  right: -5px; /* 定位到右侧 */
-}
-::v-deep .ant-badge.ant-badge-status .ant-badge-status-dot{
-  width: 7px;
-  height: 7px;
-}
+    position: absolute; /* 绝对定位 */
+    bottom: -5px; /* 定位到底部 */
+    right: -5px; /* 定位到右侧 */
+  }
+  ::v-deep .ant-badge.ant-badge-status .ant-badge-status-dot {
+    width: 7px;
+    height: 7px;
+  }
+  .room-container-body {
+    position: relative;
+    flex: 1;
+    overflow: auto;
+    display: flex;
+    flex-direction: column;
+    padding: 10px 10px 0 10px;
+    width: 100%;
+    // background: pink;
+    height: calc(100% - 53px);
+  }
+  .chat-roomings-tip-box {
+    line-height: 36px;
+    background: #f1f5fb;
+    box-shadow: 0 2px 6px 0 rgba(4, 29, 85, 0.14);
+    text-align: center;
+    position: absolute;
+    width: 100%;
+    top: 0;
+    left: 0;
+    z-index: 100;
+  }
+  .chat-roomings-tip-btn {
+    margin-left: 8px;
+    background: #e0e9fb;
+    // padding: 7px 15px;
+    font-size: 12px;
+    border-radius: 3px;
+    display: inline-block;
+    line-height: 1;
+    white-space: nowrap;
+    cursor: pointer;
+    background: #fff;
+    border: 1px solid #dcdfe6;
+    border-color: #dcdfe6;
+    color: #606266;
+    text-align: center;
+    box-sizing: border-box;
+    outline: none;
+    margin: 0;
+    transition: 0.1s;
+    font-weight: 400;
+  }
+  .room-container-body-messages {
+    display: flex;
+    flex-direction: column;
+    padding: 10px;
+    width: 100%;
+    overflow-y: auto;
+    flex-grow: 1;
+  }
+  .room-container__loading {
+    height: 44px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-size: 14px;
+    color: #c5c5c5;
+    margin-bottom: 16px;
+  }
+
+  .chat-roomings__message {
+    position: relative;
+    height: 100%;
+    background: #fff;
+  }
+  .send-message {
+    height: 100%;
+    background: #fcfcfc;
+  }
+  .editor{
+    position: static;
+  }
+  .header{
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    padding: 0 16px 6px 0;
+    background: #fcfcfc;
+    margin-top: 15px;
+  }
+  .left-part{
+    display: flex;
+  }
+  .img-emo{
+    width: 18px;
+    height: 18px;
+    background-size: contain;
+    margin: 0 10px;
+    background-image: url('@/assets/images/icon-emoji.png');
+  }
 </style>

+ 80 - 11
src/views/wechat/wx/WxDrawer.vue

@@ -10,7 +10,11 @@
   >
     <BasicForm @register="registerForm" />
     <template #appendFooter>
-      <a-button @click="showQRCode">获取登陆二维码</a-button>
+      <a-button v-if="drawerTitle == '添加微信'" @click="showQRCode">获取登陆二维码</a-button>
+      <a-button v-if="drawerTitle == '编辑微信'" @click="handleCancel">取消</a-button>
+      <a-button type="primary" v-if="drawerTitle == '编辑微信'" @click="handleSuccess">
+        确认
+      </a-button>
     </template>
   </BasicDrawer>
   <BasicModal
@@ -29,12 +33,13 @@
   </BasicModal>
 </template>
 <script lang="ts">
-  import { defineComponent, ref, computed, unref } from 'vue';
+  import { defineComponent, ref, computed, unref, onMounted } from 'vue';
   import { BasicForm, useForm } from '@/components/Form/index';
-  import { formSchema } from './wx.data';
+  import { formSchema as baseFormSchema } from './wx.data';
   import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
   import { BasicModal, useModal } from '/@/components/Modal';
   import { useI18n } from 'vue-i18n';
+  import { getAgentList } from '@/api/wechat/agent';
 
   import { createWx, updateWx } from '@/api/wechat/wx';
   import { refreshLoginQRApi } from '@/api/wechat/wxhook';
@@ -43,16 +48,41 @@
     name: 'WxDrawer',
     components: { BasicDrawer, BasicForm, BasicModal },
     emits: ['success', 'register'],
-    setup(_, { emit }) {
+
+    setup(props, { emit }) {
       const isUpdate = ref(true);
       const { t } = useI18n();
       let modalContent = ref('');
+      const modeList = ref([]);
+      const drawerTitle = ref('');
+      let recordAgentId = ref(undefined);
 
+      let recordId = ref(undefined);
       const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
         labelWidth: 160,
         baseColProps: { span: 24 },
         layout: 'vertical',
-        schemas: formSchema,
+        schemas: computed(() => {
+          return baseFormSchema.map((field) => {
+            if (field.field === 'mode') {
+              const options = [
+                { label: '知识库', value: 0 }, // 默认选项
+                ...modeList.value.map((item) => ({
+                  label: item.name,
+                  value: item.id,
+                })),
+              ];
+
+              return {
+                ...field,
+                componentProps: {
+                  options,
+                },
+              };
+            }
+            return field;
+          });
+        }),
         showActionButtonGroup: false,
       });
 
@@ -63,16 +93,49 @@
         isUpdate.value = !!data?.isUpdate;
 
         if (unref(isUpdate)) {
-          setFieldsValue({
+          recordAgentId.value = data?.record?.agentId;
+
+          recordId.value = data?.record?.id;
+          const formValues = {
             ...data.record,
-          });
+            mode: data.record.agentInfo.name, // 确保正确提取和映射值
+          };
+
+          setFieldsValue(formValues);
         }
       });
 
+      onMounted(async () => {
+        let res = await getAgentList({ page: 1, pageSize: 1000 });
+        modeList.value = res.data.data.map((item) => ({
+          name: item.name,
+          id: item.id,
+        }));
+      });
       const getTitle = computed(() =>
-        !unref(isUpdate) ? t('wechat.wx.addWx') : t('wechat.wx.editWx'),
+        !unref(isUpdate) ? (drawerTitle.value = '添加微信') : (drawerTitle.value = '编辑微信'),
       );
 
+      async function handleSuccess() {
+        const values = await validate();
+        console.log(values)
+        let agentId;
+        if (values.mode === 0) {
+           agentId = 0;
+        } else {
+           agentId = recordAgentId.value;
+        }
+        const { callback, serverId, port } = values;
+        const id = recordId.value;
+        let res = await updateWx({ callback, serverId, port, agentId, id });
+        console.log(res);
+        closeDrawer();
+        emit('success');
+      }
+
+      function handleCancel() {
+        closeDrawer();
+      }
       const [registerModal, { openModal, setModalProps, closeModal }] = useModal();
       async function handleSubmit() {
         const values = await validate();
@@ -93,13 +156,13 @@
         let result = await refreshLoginQRApi(values);
         if (result.code === 0) {
           if (result.data.status === '0' || result.data.status === '5') {
-            setModalProps({ showOkBtn:true });
+            setModalProps({ showOkBtn: true });
             modalContent.value = `<img src="${result.data.qRCode}" />`;
           } else if (result.data.status === '3' && unref(isUpdate)) {
-            setModalProps({ showOkBtn:false });
+            setModalProps({ showOkBtn: false });
             modalContent.value = `<p><b>${result.data.statusDesc}</b></p><p>如果需要更换账号,您需要先退出登陆~</p>`;
           } else {
-            setModalProps({ showOkBtn:false });
+            setModalProps({ showOkBtn: false });
             modalContent.value = `<p><b>${result.data.statusDesc}</b></p>`;
           }
           openModal(true);
@@ -114,6 +177,12 @@
         registerModal,
         showQRCode,
         modalContent,
+        drawerTitle,
+        handleSuccess,
+        handleCancel,
+        modeList,
+        recordAgentId,
+        recordId,
       };
     },
   });

+ 5 - 5
src/views/wechat/wx/index.vue

@@ -10,10 +10,10 @@
         <template v-if="column.key === 'action'">
           <TableAction
             :actions="[
-              // {
-              //   icon: 'clarity:note-edit-line',
-              //   onClick: handleEdit.bind(null, record),
-              // },
+              {
+                icon: 'clarity:note-edit-line',
+                onClick: handleEdit.bind(null, record),
+              },
               {
                 icon: 'ant-design:login-outlined',
                 onClick: handleLogin.bind(null, record),
@@ -106,7 +106,7 @@ import { refreshLoginQRApi } from '@/api/wechat/wxhook'; getPermCode
         showIndexColumn: false,
         clickToRowSelect: false,
         actionColumn: {
-          width: 60,
+          width: 90,
           title: t('common.action'),
           dataIndex: 'action',
           fixed: undefined,

+ 30 - 3
src/views/wechat/wx/wx.data.ts

@@ -3,9 +3,10 @@ import { useI18n } from '@/hooks/web/useI18n'
 import { formatToDateTime } from '@/utils/dateUtil'
 import { h } from 'vue'
 import { getServerList } from '@/api/wechat/server'
-
+import { getAgentList } from '@/api/wechat/agent';
+// import { ref } from 'vue';
 const { t } = useI18n()
-
+// const modeList = ref([]);
 export const columns: BasicColumn[] = [
   {
     title: t('wechat.wx.serverId'),
@@ -73,6 +74,14 @@ export const columns: BasicColumn[] = [
       return formatToDateTime(record.createdAt)
     },
   },
+  {
+    title: '模式',
+    dataIndex: 'agentInfo.name',
+    width: 50,
+    customRender: ({ record }) => {
+      return record.agentInfo.name == null ? '知识库' : record.agentInfo.name
+    },
+  },
 ]
 
 export const searchFormSchema: FormSchema[] = [
@@ -137,6 +146,24 @@ export const formSchema: FormSchema[] = [
   {
     field: 'mode',
     label: '模式',
-    component: 'Select',
+    component: 'ApiSelect',
+    required: true,
+    componentProps: {
+      api: async () => {
+        const response = await getAgentList({
+          page: 1,
+          pageSize: 1000,
+        });
+        // 插入固定项
+        const fixedOption = {
+          id: 0,
+          name: '知识库',
+        };
+        return [fixedOption, ...response.data.data];
+      },
+      resultField: '', // 因为我们直接在 API 中返回处理过的数据,所以这里可以设置为空字符串
+      labelField: 'name',
+      valueField: 'id',
+    },
   },
 ]