Explorar o código

Merge branch 'master' of http://git.ascrm.cn:3000/scrm/wechat-ui

kyoyue hai 4 meses
pai
achega
2bf0fff9b8

+ 74 - 0
src/api/wechat/chatRecords.ts

@@ -0,0 +1,74 @@
+import { defHttp } from '@/utils/http/axios';
+import { ErrorMessageMode } from '/#/axios';
+import { BaseDataResp, BaseListReq, BaseResp, BaseIDsReq, BaseIDReq } from '@/api/model/baseModel';
+import { ChatRecordsInfo, ChatRecordsListResp } from './model/chatRecordsModel';
+
+enum Api {
+  CreateChatRecords = '/wechat-api/chat_records/create',
+  UpdateChatRecords = '/wechat-api/chat_records/update',
+  GetChatRecordsList = '/wechat-api/chat_records/list',
+  DeleteChatRecords = '/wechat-api/chat_records/delete',
+  GetChatRecordsById = '/wechat-api/chat_records',
+}
+
+/**
+ * @description: Get chat records list
+ */
+
+export const getChatRecordsList = (params: BaseListReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<ChatRecordsListResp>>(
+    { url: Api.GetChatRecordsList, params },
+    { errorMessageMode: mode },
+  );
+};
+
+/**
+ *  @description: Create a new chat records
+ */
+export const createChatRecords = (params: ChatRecordsInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.CreateChatRecords, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Update the chat records
+ */
+export const updateChatRecords = (params: ChatRecordsInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.UpdateChatRecords, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Delete chat recordss
+ */
+export const deleteChatRecords = (params: BaseIDsReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.DeleteChatRecords, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Get chat records By ID
+ */
+export const getChatRecordsById = (params: BaseIDReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<ChatRecordsInfo>>(
+    { url: Api.GetChatRecordsById, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
+};

+ 74 - 0
src/api/wechat/chatSession.ts

@@ -0,0 +1,74 @@
+import { defHttp } from '@/utils/http/axios';
+import { ErrorMessageMode } from '/#/axios';
+import { BaseDataResp, BaseListReq, BaseResp, BaseIDsReq, BaseIDReq } from '@/api/model/baseModel';
+import { ChatSessionInfo, ChatSessionListResp } from './model/chatSessionModel';
+
+enum Api {
+  CreateChatSession = '/wechat-api/chat_session/create',
+  UpdateChatSession = '/wechat-api/chat_session/update',
+  GetChatSessionList = '/wechat-api/chat_session/list',
+  DeleteChatSession = '/wechat-api/chat_session/delete',
+  GetChatSessionById = '/wechat-api/chat_session',
+}
+
+/**
+ * @description: Get chat session list
+ */
+
+export const getChatSessionList = (params: BaseListReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<ChatSessionListResp>>(
+    { url: Api.GetChatSessionList, params },
+    { errorMessageMode: mode },
+  );
+};
+
+/**
+ *  @description: Create a new chat session
+ */
+export const createChatSession = (params: ChatSessionInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.CreateChatSession, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Update the chat session
+ */
+export const updateChatSession = (params: ChatSessionInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.UpdateChatSession, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Delete chat sessions
+ */
+export const deleteChatSession = (params: BaseIDsReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.DeleteChatSession, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Get chat session By ID
+ */
+export const getChatSessionById = (params: BaseIDReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<ChatSessionInfo>>(
+    { url: Api.GetChatSessionById, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
+};

+ 22 - 0
src/api/wechat/model/chatRecordsModel.ts

@@ -0,0 +1,22 @@
+import { BaseListResp } from '@/api/model/baseModel';
+
+/**
+ *  @description: ChatRecords info response
+ */
+export interface ChatRecordsInfo {
+  id?: number;
+  createdAt?: number;
+  updatedAt?: number;
+  content?: string;
+  contentType?: number;
+  sessionId?: number;
+  userId?: number;
+  botId?: number;
+  botType?: number;
+}
+
+/**
+ *  @description: ChatRecords list response
+ */
+
+export type ChatRecordsListResp = BaseListResp<ChatRecordsInfo>;

+ 20 - 0
src/api/wechat/model/chatSessionModel.ts

@@ -0,0 +1,20 @@
+import { BaseListResp } from '@/api/model/baseModel';
+
+/**
+ *  @description: ChatSession info response
+ */
+export interface ChatSessionInfo {
+  id?: number;
+  createdAt?: number;
+  updatedAt?: number;
+  name?: string;
+  userId?: number;
+  botId?: number;
+  botType?: number;
+}
+
+/**
+ *  @description: ChatSession list response
+ */
+
+export type ChatSessionListResp = BaseListResp<ChatSessionInfo>;

+ 31 - 0
src/api/wechat/model/wxCardModel.ts

@@ -0,0 +1,31 @@
+import { BaseListResp } from '@/api/model/baseModel';
+
+/**
+ *  @description: WxCard info response
+ */
+export interface WxCardInfo {
+  id?: number;
+  createdAt?: number;
+  updatedAt?: number;
+  userId?: number;
+  wxUserId?: number;
+  avatar?: string;
+  logo?: string;
+  name?: string;
+  company?: string;
+  address?: string;
+  phone?: string;
+  officialAccount?: string;
+  wechatAccount?: string;
+  email?: string;
+  apiBase?: string;
+  apiKey?: string;
+  aiInfo?: string;
+  intro?: string;
+}
+
+/**
+ *  @description: WxCard list response
+ */
+
+export type WxCardListResp = BaseListResp<WxCardInfo>;

+ 23 - 0
src/api/wechat/model/wxCardUserModel.ts

@@ -0,0 +1,23 @@
+import { BaseListResp } from '@/api/model/baseModel';
+
+/**
+ *  @description: WxCardUser info response
+ */
+export interface WxCardUserInfo {
+  id?: number;
+  createdAt?: number;
+  updatedAt?: number;
+  wxid?: string;
+  account?: string;
+  avatar?: string;
+  nickname?: string;
+  remark?: string;
+  phone?: string;
+  openId?: string;
+}
+
+/**
+ *  @description: WxCardUser list response
+ */
+
+export type WxCardUserListResp = BaseListResp<WxCardUserInfo>;

+ 20 - 0
src/api/wechat/model/wxCardVisitModel.ts

@@ -0,0 +1,20 @@
+import { BaseListResp } from '@/api/model/baseModel';
+
+/**
+ *  @description: WxCardVisit info response
+ */
+export interface WxCardVisitInfo {
+  id?: number;
+  createdAt?: number;
+  updatedAt?: number;
+  userId?: number;
+  botId?: number;
+  botType?: number;
+  cardInfo?: WxCardSimpleInfo;
+}
+
+/**
+ *  @description: WxCardVisit list response
+ */
+
+export type WxCardVisitListResp = BaseListResp<WxCardVisitInfo>;

+ 74 - 0
src/api/wechat/wxCard.ts

@@ -0,0 +1,74 @@
+import { defHttp } from '@/utils/http/axios';
+import { ErrorMessageMode } from '/#/axios';
+import { BaseDataResp, BaseListReq, BaseResp, BaseIDsReq, BaseIDReq } from '@/api/model/baseModel';
+import { WxCardInfo, WxCardListResp } from './model/wxCardModel';
+
+enum Api {
+  CreateWxCard = '/wechat-api/wx_card/create',
+  UpdateWxCard = '/wechat-api/wx_card/update',
+  GetWxCardList = '/wechat-api/wx_card/list',
+  DeleteWxCard = '/wechat-api/wx_card/delete',
+  GetWxCardById = '/wechat-api/wx_card',
+}
+
+/**
+ * @description: Get wx card list
+ */
+
+export const getWxCardList = (params: BaseListReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<WxCardListResp>>(
+    { url: Api.GetWxCardList, params },
+    { errorMessageMode: mode },
+  );
+};
+
+/**
+ *  @description: Create a new wx card
+ */
+export const createWxCard = (params: WxCardInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.CreateWxCard, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Update the wx card
+ */
+export const updateWxCard = (params: WxCardInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.UpdateWxCard, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Delete wx cards
+ */
+export const deleteWxCard = (params: BaseIDsReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.DeleteWxCard, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Get wx card By ID
+ */
+export const getWxCardById = (params: BaseIDReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<WxCardInfo>>(
+    { url: Api.GetWxCardById, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
+};

+ 74 - 0
src/api/wechat/wxCardUser.ts

@@ -0,0 +1,74 @@
+import { defHttp } from '@/utils/http/axios';
+import { ErrorMessageMode } from '/#/axios';
+import { BaseDataResp, BaseListReq, BaseResp, BaseIDsReq, BaseIDReq } from '@/api/model/baseModel';
+import { WxCardUserInfo, WxCardUserListResp } from './model/wxCardUserModel';
+
+enum Api {
+  CreateWxCardUser = '/wechat-api/wx_card_user/create',
+  UpdateWxCardUser = '/wechat-api/wx_card_user/update',
+  GetWxCardUserList = '/wechat-api/wx_card_user/list',
+  DeleteWxCardUser = '/wechat-api/wx_card_user/delete',
+  GetWxCardUserById = '/wechat-api/wx_card_user',
+}
+
+/**
+ * @description: Get wx card user list
+ */
+
+export const getWxCardUserList = (params: BaseListReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<WxCardUserListResp>>(
+    { url: Api.GetWxCardUserList, params },
+    { errorMessageMode: mode },
+  );
+};
+
+/**
+ *  @description: Create a new wx card user
+ */
+export const createWxCardUser = (params: WxCardUserInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.CreateWxCardUser, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Update the wx card user
+ */
+export const updateWxCardUser = (params: WxCardUserInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.UpdateWxCardUser, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Delete wx card users
+ */
+export const deleteWxCardUser = (params: BaseIDsReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.DeleteWxCardUser, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Get wx card user By ID
+ */
+export const getWxCardUserById = (params: BaseIDReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<WxCardUserInfo>>(
+    { url: Api.GetWxCardUserById, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
+};

+ 74 - 0
src/api/wechat/wxCardVisit.ts

@@ -0,0 +1,74 @@
+import { defHttp } from '@/utils/http/axios';
+import { ErrorMessageMode } from '/#/axios';
+import { BaseDataResp, BaseListReq, BaseResp, BaseIDsReq, BaseIDReq } from '@/api/model/baseModel';
+import { WxCardVisitInfo, WxCardVisitListResp } from './model/wxCardVisitModel';
+
+enum Api {
+  CreateWxCardVisit = '/wechat-api/wx_card_visit/create',
+  UpdateWxCardVisit = '/wechat-api/wx_card_visit/update',
+  GetWxCardVisitList = '/wechat-api/wx_card_visit/list',
+  DeleteWxCardVisit = '/wechat-api/wx_card_visit/delete',
+  GetWxCardVisitById = '/wechat-api/wx_card_visit',
+}
+
+/**
+ * @description: Get wx card visit list
+ */
+
+export const getWxCardVisitList = (params: BaseListReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<WxCardVisitListResp>>(
+    { url: Api.GetWxCardVisitList, params },
+    { errorMessageMode: mode },
+  );
+};
+
+/**
+ *  @description: Create a new wx card visit
+ */
+export const createWxCardVisit = (params: WxCardVisitInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.CreateWxCardVisit, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Update the wx card visit
+ */
+export const updateWxCardVisit = (params: WxCardVisitInfo, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.UpdateWxCardVisit, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Delete wx card visits
+ */
+export const deleteWxCardVisit = (params: BaseIDsReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseResp>(
+    { url: Api.DeleteWxCardVisit, params: params },
+    {
+      errorMessageMode: mode,
+      successMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: Get wx card visit By ID
+ */
+export const getWxCardVisitById = (params: BaseIDReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<WxCardVisitInfo>>(
+    { url: Api.GetWxCardVisitById, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
+};

+ 60 - 5
src/locales/lang/en/wechat.ts

@@ -132,10 +132,65 @@ export default {
     editToken: 'Edit Token',
     tokenList: 'Token List',
   },
-  agentBase: {
-    id: 'Id',
-    addAgentBase: 'Add AgentBase',
-    editAgentBase: 'Edit AgentBase',
-    agentBaseList: 'AgentBase List',
+  chatRecords: {
+    content: 'Content',
+    contentType: 'ContentType',
+    sessionId: 'SessionId',
+    userId: 'UserId',
+    botId: 'BotId',
+    botType: 'BotType',
+    addChatRecords: 'Add ChatRecords',
+    editChatRecords: 'Edit ChatRecords',
+    chatRecordsList: 'ChatRecords List',
+  },
+  chatSession: {
+    name: 'Name',
+    userId: 'UserId',
+    botId: 'BotId',
+    botType: 'BotType',
+    addChatSession: 'Add ChatSession',
+    editChatSession: 'Edit ChatSession',
+    chatSessionList: 'ChatSession List',
+  },
+  wxCard: {
+    userId: 'UserId',
+    wxUserId: 'WxUserId',
+    avatar: 'Avatar',
+    logo: 'Logo',
+    name: 'Name',
+    company: 'Company',
+    address: 'Address',
+    phone: 'Phone',
+    officialAccount: 'OfficialAccount',
+    wechatAccount: 'WechatAccount',
+    email: 'Email',
+    apiBase: 'ApiBase',
+    apiKey: 'ApiKey',
+    aiInfo: 'AiInfo',
+    intro: 'Intro',
+    addWxCard: 'Add WxCard',
+    editWxCard: 'Edit WxCard',
+    wxCardList: 'WxCard List',
+  },
+  wxCardUser: {
+    wxid: 'Wxid',
+    account: 'Account',
+    avatar: 'Avatar',
+    nickname: 'Nickname',
+    remark: 'Remark',
+    phone: 'Phone',
+    openId: 'OpenId',
+    addWxCardUser: 'Add WxCardUser',
+    editWxCardUser: 'Edit WxCardUser',
+    wxCardUserList: 'WxCardUser List',
+  },
+  wxCardVisit: {
+    userId: 'UserId',
+    botId: 'BotId',
+    botType: 'BotType',
+    cardInfo: 'CardInfo',
+    addWxCardVisit: 'Add WxCardVisit',
+    editWxCardVisit: 'Edit WxCardVisit',
+    wxCardVisitList: 'WxCardVisit List',
   },
 };

+ 60 - 5
src/locales/lang/zh-CN/wechat.ts

@@ -136,10 +136,65 @@ export default {
     editToken: '编辑 Token',
     tokenList: 'Token 列表',
   },
-  agentBase: {
-    id: 'Id',
-    addAgentBase: '添加 AgentBase',
-    editAgentBase: '编辑 AgentBase',
-    agentBaseList: 'AgentBase 列表',
+  chatRecords: {
+    content: 'Content',
+    contentType: 'ContentType',
+    sessionId: 'SessionId',
+    userId: 'UserId',
+    botId: 'BotId',
+    botType: 'BotType',
+    addChatRecords: '添加 ChatRecords',
+    editChatRecords: '编辑 ChatRecords',
+    chatRecordsList: 'ChatRecords 列表',
+  },
+  chatSession: {
+    name: 'Name',
+    userId: 'UserId',
+    botId: 'BotId',
+    botType: 'BotType',
+    addChatSession: '添加 ChatSession',
+    editChatSession: '编辑 ChatSession',
+    chatSessionList: 'ChatSession 列表',
+  },
+  wxCard: {
+    userId: 'UserId',
+    wxUserId: 'WxUserId',
+    avatar: 'Avatar',
+    logo: 'Logo',
+    name: 'Name',
+    company: 'Company',
+    address: 'Address',
+    phone: 'Phone',
+    officialAccount: 'OfficialAccount',
+    wechatAccount: 'WechatAccount',
+    email: 'Email',
+    apiBase: 'ApiBase',
+    apiKey: 'ApiKey',
+    aiInfo: 'AiInfo',
+    intro: 'Intro',
+    addWxCard: '添加 WxCard',
+    editWxCard: '编辑 WxCard',
+    wxCardList: 'WxCard 列表',
+  },
+  wxCardUser: {
+    wxid: 'Wxid',
+    account: 'Account',
+    avatar: 'Avatar',
+    nickname: 'Nickname',
+    remark: 'Remark',
+    phone: 'Phone',
+    openId: 'OpenId',
+    addWxCardUser: '添加 WxCardUser',
+    editWxCardUser: '编辑 WxCardUser',
+    wxCardUserList: 'WxCardUser 列表',
+  },
+  wxCardVisit: {
+    userId: 'UserId',
+    botId: 'BotId',
+    botType: 'BotType',
+    cardInfo: 'CardInfo',
+    addWxCardVisit: '添加 WxCardVisit',
+    editWxCardVisit: '编辑 WxCardVisit',
+    wxCardVisitList: 'WxCardVisit 列表',
   },
 };

+ 75 - 0
src/views/wechat/chat_records/ChatRecordsDrawer.vue

@@ -0,0 +1,75 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :title="getTitle"
+    width="35%"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" />
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '@/components/Form/index';
+  import { formSchema } from './chatRecords.data';
+  import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
+  import { useI18n } from 'vue-i18n';
+
+  import { createChatRecords, updateChatRecords } from '@/api/wechat/chatRecords';
+
+  export default defineComponent({
+    name: 'ChatRecordsDrawer',
+    components: { BasicDrawer, BasicForm },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      const { t } = useI18n();
+
+      const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
+        labelWidth: 160,
+        baseColProps: { span: 24 },
+        layout: 'vertical',
+        schemas: formSchema,
+        showActionButtonGroup: false,
+      });
+
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        setDrawerProps({ confirmLoading: false });
+
+        isUpdate.value = !!data?.isUpdate;
+
+        if (unref(isUpdate)) {
+          setFieldsValue({
+            ...data.record,
+          });
+        }
+      });
+
+      const getTitle = computed(() =>
+        !unref(isUpdate) ? t('wechat.chatRecords.addChatRecords') : t('wechat.chatRecords.editChatRecords'),
+      );
+
+      async function handleSubmit() {
+        const values = await validate();
+        setDrawerProps({ confirmLoading: true });
+        values['id'] = unref(isUpdate) ? Number(values['id']) : 0;
+        let result = unref(isUpdate) ? await updateChatRecords(values) : await createChatRecords(values);
+        if (result.code === 0) {
+          closeDrawer();
+          emit('success');
+        }
+        setDrawerProps({ confirmLoading: false });
+      }
+
+      return {
+        registerDrawer,
+        registerForm,
+        getTitle,
+        handleSubmit,
+      };
+    },
+  });
+</script>

+ 112 - 0
src/views/wechat/chat_records/chatRecords.data.ts

@@ -0,0 +1,112 @@
+import { BasicColumn, FormSchema } from '@/components/Table';
+import { useI18n } from '@/hooks/web/useI18n';
+import { formatToDateTime } from '@/utils/dateUtil';
+
+const { t } = useI18n();
+
+export const columns: BasicColumn[] = [
+  {
+    title: t('wechat.chatRecords.content'),
+    dataIndex: 'content',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatRecords.contentType'),
+    dataIndex: 'contentType',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatRecords.sessionId'),
+    dataIndex: 'sessionId',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatRecords.userId'),
+    dataIndex: 'userId',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatRecords.botId'),
+    dataIndex: 'botId',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatRecords.botType'),
+    dataIndex: 'botType',
+    width: 100,
+  },
+  {
+    title: t('common.createTime'),
+    dataIndex: 'createdAt',
+    width: 70,
+    customRender: ({ record }) => {
+      return formatToDateTime(record.createdAt);
+    },
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'sessionId',
+    label: t('wechat.chatRecords.sessionId'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+  {
+    field: 'botId',
+    label: t('wechat.chatRecords.botId'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+  {
+    field: 'botType',
+    label: t('wechat.chatRecords.botType'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    field: 'id',
+    label: 'ID',
+    component: 'Input',
+    show: false,
+  },
+  {
+    field: 'content',
+    label: t('wechat.chatRecords.content'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'contentType',
+    label: t('wechat.chatRecords.contentType'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'sessionId',
+    label: t('wechat.chatRecords.sessionId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'userId',
+    label: t('wechat.chatRecords.userId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'botId',
+    label: t('wechat.chatRecords.botId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'botType',
+    label: t('wechat.chatRecords.botType'),
+    component: 'InputNumber',
+    required: true,
+  },
+];

+ 152 - 0
src/views/wechat/chat_records/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #tableTitle>
+        <Button
+          type="primary"
+          danger
+          preIcon="ant-design:delete-outlined"
+          v-if="showDeleteButton"
+          @click="handleBatchDelete"
+        >
+          {{ t('common.delete') }}
+        </Button>
+      </template>
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate">
+          {{ t('wechat.chatRecords.addChatRecords') }}
+        </a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                icon: 'clarity:note-edit-line',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                icon: 'ant-design:delete-outlined',
+                color: 'error',
+                popConfirm: {
+                  title: t('common.deleteConfirm'),
+                  placement: 'left',
+                  confirm: handleDelete.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <ChatRecordsDrawer @register="registerDrawer" @success="handleSuccess" />
+  </div>
+</template>
+<script lang="ts">
+  import { createVNode, defineComponent, ref } from 'vue';
+  import { Modal } from 'ant-design-vue';
+  import { ExclamationCircleOutlined } from '@ant-design/icons-vue/lib/icons';
+  import { BasicTable, useTable, TableAction } from '@/components/Table';
+  import { Button } from '@/components/Button';
+
+  import { useDrawer } from '@/components/Drawer';
+  import ChatRecordsDrawer from './ChatRecordsDrawer.vue';
+  import { useI18n } from 'vue-i18n';
+
+  import { columns, searchFormSchema } from './chatRecords.data';
+  import { getChatRecordsList, deleteChatRecords } from '@/api/wechat/chatRecords';
+
+  export default defineComponent({
+    name: 'ChatRecordsManagement',
+    components: { BasicTable, ChatRecordsDrawer, TableAction, Button },
+    setup() {
+      const { t } = useI18n();
+      const selectedIds = ref<number[] | string[]>();
+      const showDeleteButton = ref<boolean>(false);
+
+      const [registerDrawer, { openDrawer }] = useDrawer();
+      const [registerTable, { reload }] = useTable({
+        title: t('wechat.chatRecords.chatRecordsList'),
+        api: getChatRecordsList,
+        columns,
+        formConfig: {
+          labelWidth: 120,
+          schemas: searchFormSchema,
+        },
+        useSearchForm: true,
+        showTableSetting: true,
+        bordered: true,
+        showIndexColumn: false,
+        clickToRowSelect: false,
+        actionColumn: {
+          width: 30,
+          title: t('common.action'),
+          dataIndex: 'action',
+          fixed: undefined,
+        },
+        rowKey: 'id',
+        rowSelection: {
+          type: 'checkbox',
+          columnWidth: 20,
+          onChange: (selectedRowKeys, _selectedRows) => {
+            selectedIds.value = selectedRowKeys as number[];
+            showDeleteButton.value = selectedRowKeys.length > 0;
+          },
+        },
+      });
+
+      function handleCreate() {
+        openDrawer(true, {
+          isUpdate: false,
+        });
+      }
+
+      function handleEdit(record: Recordable) {
+        openDrawer(true, {
+          record,
+          isUpdate: true,
+        });
+      }
+
+      async function handleDelete(record: Recordable) {
+        const result = await deleteChatRecords({ ids: [record.id] });
+        if (result.code === 0) {
+          await reload();
+        }
+      }
+
+      async function handleBatchDelete() {
+        Modal.confirm({
+          title: t('common.deleteConfirm'),
+          icon: createVNode(ExclamationCircleOutlined),
+          async onOk() {
+            const result = await deleteChatRecords({ ids: selectedIds.value as number[] });
+            if (result.code === 0) {
+              showDeleteButton.value = false;
+              await reload();
+            }
+          },
+          onCancel() {
+            console.log('Cancel');
+          },
+        });
+      }
+
+      async function handleSuccess() {
+        await reload();
+      }
+
+      return {
+        t,
+        registerTable,
+        registerDrawer,
+        handleCreate,
+        handleEdit,
+        handleDelete,
+        handleSuccess,
+        handleBatchDelete,
+        showDeleteButton,
+      };
+    },
+  });
+</script>

+ 75 - 0
src/views/wechat/chat_session/ChatSessionDrawer.vue

@@ -0,0 +1,75 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :title="getTitle"
+    width="35%"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" />
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '@/components/Form/index';
+  import { formSchema } from './chatSession.data';
+  import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
+  import { useI18n } from 'vue-i18n';
+
+  import { createChatSession, updateChatSession } from '@/api/wechat/chatSession';
+
+  export default defineComponent({
+    name: 'ChatSessionDrawer',
+    components: { BasicDrawer, BasicForm },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      const { t } = useI18n();
+
+      const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
+        labelWidth: 160,
+        baseColProps: { span: 24 },
+        layout: 'vertical',
+        schemas: formSchema,
+        showActionButtonGroup: false,
+      });
+
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        setDrawerProps({ confirmLoading: false });
+
+        isUpdate.value = !!data?.isUpdate;
+
+        if (unref(isUpdate)) {
+          setFieldsValue({
+            ...data.record,
+          });
+        }
+      });
+
+      const getTitle = computed(() =>
+        !unref(isUpdate) ? t('wechat.chatSession.addChatSession') : t('wechat.chatSession.editChatSession'),
+      );
+
+      async function handleSubmit() {
+        const values = await validate();
+        setDrawerProps({ confirmLoading: true });
+        values['id'] = unref(isUpdate) ? Number(values['id']) : 0;
+        let result = unref(isUpdate) ? await updateChatSession(values) : await createChatSession(values);
+        if (result.code === 0) {
+          closeDrawer();
+          emit('success');
+        }
+        setDrawerProps({ confirmLoading: false });
+      }
+
+      return {
+        registerDrawer,
+        registerForm,
+        getTitle,
+        handleSubmit,
+      };
+    },
+  });
+</script>

+ 78 - 0
src/views/wechat/chat_session/chatSession.data.ts

@@ -0,0 +1,78 @@
+import { BasicColumn, FormSchema } from '@/components/Table';
+import { useI18n } from '@/hooks/web/useI18n';
+import { formatToDateTime } from '@/utils/dateUtil';
+
+const { t } = useI18n();
+
+export const columns: BasicColumn[] = [
+  {
+    title: t('wechat.chatSession.name'),
+    dataIndex: 'name',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatSession.userId'),
+    dataIndex: 'userId',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatSession.botId'),
+    dataIndex: 'botId',
+    width: 100,
+  },
+  {
+    title: t('wechat.chatSession.botType'),
+    dataIndex: 'botType',
+    width: 100,
+  },
+  {
+    title: t('common.createTime'),
+    dataIndex: 'createdAt',
+    width: 70,
+    customRender: ({ record }) => {
+      return formatToDateTime(record.createdAt);
+    },
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'botType',
+    label: t('wechat.chatSession.botType'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    field: 'id',
+    label: 'ID',
+    component: 'Input',
+    show: false,
+  },
+  {
+    field: 'name',
+    label: t('wechat.chatSession.name'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'userId',
+    label: t('wechat.chatSession.userId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'botId',
+    label: t('wechat.chatSession.botId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'botType',
+    label: t('wechat.chatSession.botType'),
+    component: 'InputNumber',
+    required: true,
+  },
+];

+ 152 - 0
src/views/wechat/chat_session/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #tableTitle>
+        <Button
+          type="primary"
+          danger
+          preIcon="ant-design:delete-outlined"
+          v-if="showDeleteButton"
+          @click="handleBatchDelete"
+        >
+          {{ t('common.delete') }}
+        </Button>
+      </template>
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate">
+          {{ t('wechat.chatSession.addChatSession') }}
+        </a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                icon: 'clarity:note-edit-line',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                icon: 'ant-design:delete-outlined',
+                color: 'error',
+                popConfirm: {
+                  title: t('common.deleteConfirm'),
+                  placement: 'left',
+                  confirm: handleDelete.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <ChatSessionDrawer @register="registerDrawer" @success="handleSuccess" />
+  </div>
+</template>
+<script lang="ts">
+  import { createVNode, defineComponent, ref } from 'vue';
+  import { Modal } from 'ant-design-vue';
+  import { ExclamationCircleOutlined } from '@ant-design/icons-vue/lib/icons';
+  import { BasicTable, useTable, TableAction } from '@/components/Table';
+  import { Button } from '@/components/Button';
+
+  import { useDrawer } from '@/components/Drawer';
+  import ChatSessionDrawer from './ChatSessionDrawer.vue';
+  import { useI18n } from 'vue-i18n';
+
+  import { columns, searchFormSchema } from './chatSession.data';
+  import { getChatSessionList, deleteChatSession } from '@/api/wechat/chatSession';
+
+  export default defineComponent({
+    name: 'ChatSessionManagement',
+    components: { BasicTable, ChatSessionDrawer, TableAction, Button },
+    setup() {
+      const { t } = useI18n();
+      const selectedIds = ref<number[] | string[]>();
+      const showDeleteButton = ref<boolean>(false);
+
+      const [registerDrawer, { openDrawer }] = useDrawer();
+      const [registerTable, { reload }] = useTable({
+        title: t('wechat.chatSession.chatSessionList'),
+        api: getChatSessionList,
+        columns,
+        formConfig: {
+          labelWidth: 120,
+          schemas: searchFormSchema,
+        },
+        useSearchForm: true,
+        showTableSetting: true,
+        bordered: true,
+        showIndexColumn: false,
+        clickToRowSelect: false,
+        actionColumn: {
+          width: 30,
+          title: t('common.action'),
+          dataIndex: 'action',
+          fixed: undefined,
+        },
+        rowKey: 'id',
+        rowSelection: {
+          type: 'checkbox',
+          columnWidth: 20,
+          onChange: (selectedRowKeys, _selectedRows) => {
+            selectedIds.value = selectedRowKeys as number[];
+            showDeleteButton.value = selectedRowKeys.length > 0;
+          },
+        },
+      });
+
+      function handleCreate() {
+        openDrawer(true, {
+          isUpdate: false,
+        });
+      }
+
+      function handleEdit(record: Recordable) {
+        openDrawer(true, {
+          record,
+          isUpdate: true,
+        });
+      }
+
+      async function handleDelete(record: Recordable) {
+        const result = await deleteChatSession({ ids: [record.id] });
+        if (result.code === 0) {
+          await reload();
+        }
+      }
+
+      async function handleBatchDelete() {
+        Modal.confirm({
+          title: t('common.deleteConfirm'),
+          icon: createVNode(ExclamationCircleOutlined),
+          async onOk() {
+            const result = await deleteChatSession({ ids: selectedIds.value as number[] });
+            if (result.code === 0) {
+              showDeleteButton.value = false;
+              await reload();
+            }
+          },
+          onCancel() {
+            console.log('Cancel');
+          },
+        });
+      }
+
+      async function handleSuccess() {
+        await reload();
+      }
+
+      return {
+        t,
+        registerTable,
+        registerDrawer,
+        handleCreate,
+        handleEdit,
+        handleDelete,
+        handleSuccess,
+        handleBatchDelete,
+        showDeleteButton,
+      };
+    },
+  });
+</script>

+ 75 - 0
src/views/wechat/wx_card/WxCardDrawer.vue

@@ -0,0 +1,75 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :title="getTitle"
+    width="35%"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" />
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '@/components/Form/index';
+  import { formSchema } from './wxCard.data';
+  import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
+  import { useI18n } from 'vue-i18n';
+
+  import { createWxCard, updateWxCard } from '@/api/wechat/wxCard';
+
+  export default defineComponent({
+    name: 'WxCardDrawer',
+    components: { BasicDrawer, BasicForm },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      const { t } = useI18n();
+
+      const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
+        labelWidth: 160,
+        baseColProps: { span: 24 },
+        layout: 'vertical',
+        schemas: formSchema,
+        showActionButtonGroup: false,
+      });
+
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        setDrawerProps({ confirmLoading: false });
+
+        isUpdate.value = !!data?.isUpdate;
+
+        if (unref(isUpdate)) {
+          setFieldsValue({
+            ...data.record,
+          });
+        }
+      });
+
+      const getTitle = computed(() =>
+        !unref(isUpdate) ? t('wechat.wxCard.addWxCard') : t('wechat.wxCard.editWxCard'),
+      );
+
+      async function handleSubmit() {
+        const values = await validate();
+        setDrawerProps({ confirmLoading: true });
+        values['id'] = unref(isUpdate) ? Number(values['id']) : 0;
+        let result = unref(isUpdate) ? await updateWxCard(values) : await createWxCard(values);
+        if (result.code === 0) {
+          closeDrawer();
+          emit('success');
+        }
+        setDrawerProps({ confirmLoading: false });
+      }
+
+      return {
+        registerDrawer,
+        registerForm,
+        getTitle,
+        handleSubmit,
+      };
+    },
+  });
+</script>

+ 152 - 0
src/views/wechat/wx_card/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #tableTitle>
+        <Button
+          type="primary"
+          danger
+          preIcon="ant-design:delete-outlined"
+          v-if="showDeleteButton"
+          @click="handleBatchDelete"
+        >
+          {{ t('common.delete') }}
+        </Button>
+      </template>
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate">
+          {{ t('wechat.wxCard.addWxCard') }}
+        </a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                icon: 'clarity:note-edit-line',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                icon: 'ant-design:delete-outlined',
+                color: 'error',
+                popConfirm: {
+                  title: t('common.deleteConfirm'),
+                  placement: 'left',
+                  confirm: handleDelete.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <WxCardDrawer @register="registerDrawer" @success="handleSuccess" />
+  </div>
+</template>
+<script lang="ts">
+  import { createVNode, defineComponent, ref } from 'vue';
+  import { Modal } from 'ant-design-vue';
+  import { ExclamationCircleOutlined } from '@ant-design/icons-vue/lib/icons';
+  import { BasicTable, useTable, TableAction } from '@/components/Table';
+  import { Button } from '@/components/Button';
+
+  import { useDrawer } from '@/components/Drawer';
+  import WxCardDrawer from './WxCardDrawer.vue';
+  import { useI18n } from 'vue-i18n';
+
+  import { columns, searchFormSchema } from './wxCard.data';
+  import { getWxCardList, deleteWxCard } from '@/api/wechat/wxCard';
+
+  export default defineComponent({
+    name: 'WxCardManagement',
+    components: { BasicTable, WxCardDrawer, TableAction, Button },
+    setup() {
+      const { t } = useI18n();
+      const selectedIds = ref<number[] | string[]>();
+      const showDeleteButton = ref<boolean>(false);
+
+      const [registerDrawer, { openDrawer }] = useDrawer();
+      const [registerTable, { reload }] = useTable({
+        title: t('wechat.wxCard.wxCardList'),
+        api: getWxCardList,
+        columns,
+        formConfig: {
+          labelWidth: 120,
+          schemas: searchFormSchema,
+        },
+        useSearchForm: true,
+        showTableSetting: true,
+        bordered: true,
+        showIndexColumn: false,
+        clickToRowSelect: false,
+        actionColumn: {
+          width: 30,
+          title: t('common.action'),
+          dataIndex: 'action',
+          fixed: undefined,
+        },
+        rowKey: 'id',
+        rowSelection: {
+          type: 'checkbox',
+          columnWidth: 20,
+          onChange: (selectedRowKeys, _selectedRows) => {
+            selectedIds.value = selectedRowKeys as number[];
+            showDeleteButton.value = selectedRowKeys.length > 0;
+          },
+        },
+      });
+
+      function handleCreate() {
+        openDrawer(true, {
+          isUpdate: false,
+        });
+      }
+
+      function handleEdit(record: Recordable) {
+        openDrawer(true, {
+          record,
+          isUpdate: true,
+        });
+      }
+
+      async function handleDelete(record: Recordable) {
+        const result = await deleteWxCard({ ids: [record.id] });
+        if (result.code === 0) {
+          await reload();
+        }
+      }
+
+      async function handleBatchDelete() {
+        Modal.confirm({
+          title: t('common.deleteConfirm'),
+          icon: createVNode(ExclamationCircleOutlined),
+          async onOk() {
+            const result = await deleteWxCard({ ids: selectedIds.value as number[] });
+            if (result.code === 0) {
+              showDeleteButton.value = false;
+              await reload();
+            }
+          },
+          onCancel() {
+            console.log('Cancel');
+          },
+        });
+      }
+
+      async function handleSuccess() {
+        await reload();
+      }
+
+      return {
+        t,
+        registerTable,
+        registerDrawer,
+        handleCreate,
+        handleEdit,
+        handleDelete,
+        handleSuccess,
+        handleBatchDelete,
+        showDeleteButton,
+      };
+    },
+  });
+</script>

+ 211 - 0
src/views/wechat/wx_card/wxCard.data.ts

@@ -0,0 +1,211 @@
+import { BasicColumn, FormSchema } from '@/components/Table';
+import { useI18n } from '@/hooks/web/useI18n';
+import { formatToDateTime } from '@/utils/dateUtil';
+
+const { t } = useI18n();
+
+export const columns: BasicColumn[] = [
+  {
+    title: t('wechat.wxCard.userId'),
+    dataIndex: 'userId',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.wxUserId'),
+    dataIndex: 'wxUserId',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.avatar'),
+    dataIndex: 'avatar',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.logo'),
+    dataIndex: 'logo',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.name'),
+    dataIndex: 'name',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.company'),
+    dataIndex: 'company',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.address'),
+    dataIndex: 'address',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.phone'),
+    dataIndex: 'phone',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.officialAccount'),
+    dataIndex: 'officialAccount',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.wechatAccount'),
+    dataIndex: 'wechatAccount',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.email'),
+    dataIndex: 'email',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.apiBase'),
+    dataIndex: 'apiBase',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.apiKey'),
+    dataIndex: 'apiKey',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.aiInfo'),
+    dataIndex: 'aiInfo',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCard.intro'),
+    dataIndex: 'intro',
+    width: 100,
+  },
+  {
+    title: t('common.createTime'),
+    dataIndex: 'createdAt',
+    width: 70,
+    customRender: ({ record }) => {
+      return formatToDateTime(record.createdAt);
+    },
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'avatar',
+    label: t('wechat.wxCard.avatar'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+  {
+    field: 'logo',
+    label: t('wechat.wxCard.logo'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+  {
+    field: 'name',
+    label: t('wechat.wxCard.name'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    field: 'id',
+    label: 'ID',
+    component: 'Input',
+    show: false,
+  },
+  {
+    field: 'userId',
+    label: t('wechat.wxCard.userId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'wxUserId',
+    label: t('wechat.wxCard.wxUserId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'avatar',
+    label: t('wechat.wxCard.avatar'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'logo',
+    label: t('wechat.wxCard.logo'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'name',
+    label: t('wechat.wxCard.name'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'company',
+    label: t('wechat.wxCard.company'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'address',
+    label: t('wechat.wxCard.address'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'phone',
+    label: t('wechat.wxCard.phone'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'officialAccount',
+    label: t('wechat.wxCard.officialAccount'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'wechatAccount',
+    label: t('wechat.wxCard.wechatAccount'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'email',
+    label: t('wechat.wxCard.email'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'apiBase',
+    label: t('wechat.wxCard.apiBase'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'apiKey',
+    label: t('wechat.wxCard.apiKey'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'aiInfo',
+    label: t('wechat.wxCard.aiInfo'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'intro',
+    label: t('wechat.wxCard.intro'),
+    component: 'Input',
+    required: true,
+  },
+];

+ 75 - 0
src/views/wechat/wx_card_user/WxCardUserDrawer.vue

@@ -0,0 +1,75 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :title="getTitle"
+    width="35%"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" />
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '@/components/Form/index';
+  import { formSchema } from './wxCardUser.data';
+  import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
+  import { useI18n } from 'vue-i18n';
+
+  import { createWxCardUser, updateWxCardUser } from '@/api/wechat/wxCardUser';
+
+  export default defineComponent({
+    name: 'WxCardUserDrawer',
+    components: { BasicDrawer, BasicForm },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      const { t } = useI18n();
+
+      const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
+        labelWidth: 160,
+        baseColProps: { span: 24 },
+        layout: 'vertical',
+        schemas: formSchema,
+        showActionButtonGroup: false,
+      });
+
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        setDrawerProps({ confirmLoading: false });
+
+        isUpdate.value = !!data?.isUpdate;
+
+        if (unref(isUpdate)) {
+          setFieldsValue({
+            ...data.record,
+          });
+        }
+      });
+
+      const getTitle = computed(() =>
+        !unref(isUpdate) ? t('wechat.wxCardUser.addWxCardUser') : t('wechat.wxCardUser.editWxCardUser'),
+      );
+
+      async function handleSubmit() {
+        const values = await validate();
+        setDrawerProps({ confirmLoading: true });
+        values['id'] = unref(isUpdate) ? Number(values['id']) : 0;
+        let result = unref(isUpdate) ? await updateWxCardUser(values) : await createWxCardUser(values);
+        if (result.code === 0) {
+          closeDrawer();
+          emit('success');
+        }
+        setDrawerProps({ confirmLoading: false });
+      }
+
+      return {
+        registerDrawer,
+        registerForm,
+        getTitle,
+        handleSubmit,
+      };
+    },
+  });
+</script>

+ 152 - 0
src/views/wechat/wx_card_user/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #tableTitle>
+        <Button
+          type="primary"
+          danger
+          preIcon="ant-design:delete-outlined"
+          v-if="showDeleteButton"
+          @click="handleBatchDelete"
+        >
+          {{ t('common.delete') }}
+        </Button>
+      </template>
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate">
+          {{ t('wechat.wxCardUser.addWxCardUser') }}
+        </a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                icon: 'clarity:note-edit-line',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                icon: 'ant-design:delete-outlined',
+                color: 'error',
+                popConfirm: {
+                  title: t('common.deleteConfirm'),
+                  placement: 'left',
+                  confirm: handleDelete.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <WxCardUserDrawer @register="registerDrawer" @success="handleSuccess" />
+  </div>
+</template>
+<script lang="ts">
+  import { createVNode, defineComponent, ref } from 'vue';
+  import { Modal } from 'ant-design-vue';
+  import { ExclamationCircleOutlined } from '@ant-design/icons-vue/lib/icons';
+  import { BasicTable, useTable, TableAction } from '@/components/Table';
+  import { Button } from '@/components/Button';
+
+  import { useDrawer } from '@/components/Drawer';
+  import WxCardUserDrawer from './WxCardUserDrawer.vue';
+  import { useI18n } from 'vue-i18n';
+
+  import { columns, searchFormSchema } from './wxCardUser.data';
+  import { getWxCardUserList, deleteWxCardUser } from '@/api/wechat/wxCardUser';
+
+  export default defineComponent({
+    name: 'WxCardUserManagement',
+    components: { BasicTable, WxCardUserDrawer, TableAction, Button },
+    setup() {
+      const { t } = useI18n();
+      const selectedIds = ref<number[] | string[]>();
+      const showDeleteButton = ref<boolean>(false);
+
+      const [registerDrawer, { openDrawer }] = useDrawer();
+      const [registerTable, { reload }] = useTable({
+        title: t('wechat.wxCardUser.wxCardUserList'),
+        api: getWxCardUserList,
+        columns,
+        formConfig: {
+          labelWidth: 120,
+          schemas: searchFormSchema,
+        },
+        useSearchForm: true,
+        showTableSetting: true,
+        bordered: true,
+        showIndexColumn: false,
+        clickToRowSelect: false,
+        actionColumn: {
+          width: 30,
+          title: t('common.action'),
+          dataIndex: 'action',
+          fixed: undefined,
+        },
+        rowKey: 'id',
+        rowSelection: {
+          type: 'checkbox',
+          columnWidth: 20,
+          onChange: (selectedRowKeys, _selectedRows) => {
+            selectedIds.value = selectedRowKeys as number[];
+            showDeleteButton.value = selectedRowKeys.length > 0;
+          },
+        },
+      });
+
+      function handleCreate() {
+        openDrawer(true, {
+          isUpdate: false,
+        });
+      }
+
+      function handleEdit(record: Recordable) {
+        openDrawer(true, {
+          record,
+          isUpdate: true,
+        });
+      }
+
+      async function handleDelete(record: Recordable) {
+        const result = await deleteWxCardUser({ ids: [record.id] });
+        if (result.code === 0) {
+          await reload();
+        }
+      }
+
+      async function handleBatchDelete() {
+        Modal.confirm({
+          title: t('common.deleteConfirm'),
+          icon: createVNode(ExclamationCircleOutlined),
+          async onOk() {
+            const result = await deleteWxCardUser({ ids: selectedIds.value as number[] });
+            if (result.code === 0) {
+              showDeleteButton.value = false;
+              await reload();
+            }
+          },
+          onCancel() {
+            console.log('Cancel');
+          },
+        });
+      }
+
+      async function handleSuccess() {
+        await reload();
+      }
+
+      return {
+        t,
+        registerTable,
+        registerDrawer,
+        handleCreate,
+        handleEdit,
+        handleDelete,
+        handleSuccess,
+        handleBatchDelete,
+        showDeleteButton,
+      };
+    },
+  });
+</script>

+ 123 - 0
src/views/wechat/wx_card_user/wxCardUser.data.ts

@@ -0,0 +1,123 @@
+import { BasicColumn, FormSchema } from '@/components/Table';
+import { useI18n } from '@/hooks/web/useI18n';
+import { formatToDateTime } from '@/utils/dateUtil';
+
+const { t } = useI18n();
+
+export const columns: BasicColumn[] = [
+  {
+    title: t('wechat.wxCardUser.wxid'),
+    dataIndex: 'wxid',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardUser.account'),
+    dataIndex: 'account',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardUser.avatar'),
+    dataIndex: 'avatar',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardUser.nickname'),
+    dataIndex: 'nickname',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardUser.remark'),
+    dataIndex: 'remark',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardUser.phone'),
+    dataIndex: 'phone',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardUser.openId'),
+    dataIndex: 'openId',
+    width: 100,
+  },
+  {
+    title: t('common.createTime'),
+    dataIndex: 'createdAt',
+    width: 70,
+    customRender: ({ record }) => {
+      return formatToDateTime(record.createdAt);
+    },
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'wxid',
+    label: t('wechat.wxCardUser.wxid'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+  {
+    field: 'account',
+    label: t('wechat.wxCardUser.account'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+  {
+    field: 'avatar',
+    label: t('wechat.wxCardUser.avatar'),
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    field: 'id',
+    label: 'ID',
+    component: 'Input',
+    show: false,
+  },
+  {
+    field: 'wxid',
+    label: t('wechat.wxCardUser.wxid'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'account',
+    label: t('wechat.wxCardUser.account'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'avatar',
+    label: t('wechat.wxCardUser.avatar'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'nickname',
+    label: t('wechat.wxCardUser.nickname'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'remark',
+    label: t('wechat.wxCardUser.remark'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'phone',
+    label: t('wechat.wxCardUser.phone'),
+    component: 'Input',
+    required: true,
+  },
+  {
+    field: 'openId',
+    label: t('wechat.wxCardUser.openId'),
+    component: 'Input',
+    required: true,
+  },
+];

+ 75 - 0
src/views/wechat/wx_card_visit/WxCardVisitDrawer.vue

@@ -0,0 +1,75 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    @register="registerDrawer"
+    showFooter
+    :title="getTitle"
+    width="35%"
+    @ok="handleSubmit"
+  >
+    <BasicForm @register="registerForm" />
+  </BasicDrawer>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '@/components/Form/index';
+  import { formSchema } from './wxCardVisit.data';
+  import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
+  import { useI18n } from 'vue-i18n';
+
+  import { createWxCardVisit, updateWxCardVisit } from '@/api/wechat/wxCardVisit';
+
+  export default defineComponent({
+    name: 'WxCardVisitDrawer',
+    components: { BasicDrawer, BasicForm },
+    emits: ['success', 'register'],
+    setup(_, { emit }) {
+      const isUpdate = ref(true);
+      const { t } = useI18n();
+
+      const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
+        labelWidth: 160,
+        baseColProps: { span: 24 },
+        layout: 'vertical',
+        schemas: formSchema,
+        showActionButtonGroup: false,
+      });
+
+      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
+        resetFields();
+        setDrawerProps({ confirmLoading: false });
+
+        isUpdate.value = !!data?.isUpdate;
+
+        if (unref(isUpdate)) {
+          setFieldsValue({
+            ...data.record,
+          });
+        }
+      });
+
+      const getTitle = computed(() =>
+        !unref(isUpdate) ? t('wechat.wxCardVisit.addWxCardVisit') : t('wechat.wxCardVisit.editWxCardVisit'),
+      );
+
+      async function handleSubmit() {
+        const values = await validate();
+        setDrawerProps({ confirmLoading: true });
+        values['id'] = unref(isUpdate) ? Number(values['id']) : 0;
+        let result = unref(isUpdate) ? await updateWxCardVisit(values) : await createWxCardVisit(values);
+        if (result.code === 0) {
+          closeDrawer();
+          emit('success');
+        }
+        setDrawerProps({ confirmLoading: false });
+      }
+
+      return {
+        registerDrawer,
+        registerForm,
+        getTitle,
+        handleSubmit,
+      };
+    },
+  });
+</script>

+ 152 - 0
src/views/wechat/wx_card_visit/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #tableTitle>
+        <Button
+          type="primary"
+          danger
+          preIcon="ant-design:delete-outlined"
+          v-if="showDeleteButton"
+          @click="handleBatchDelete"
+        >
+          {{ t('common.delete') }}
+        </Button>
+      </template>
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate">
+          {{ t('wechat.wxCardVisit.addWxCardVisit') }}
+        </a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                icon: 'clarity:note-edit-line',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                icon: 'ant-design:delete-outlined',
+                color: 'error',
+                popConfirm: {
+                  title: t('common.deleteConfirm'),
+                  placement: 'left',
+                  confirm: handleDelete.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <WxCardVisitDrawer @register="registerDrawer" @success="handleSuccess" />
+  </div>
+</template>
+<script lang="ts">
+  import { createVNode, defineComponent, ref } from 'vue';
+  import { Modal } from 'ant-design-vue';
+  import { ExclamationCircleOutlined } from '@ant-design/icons-vue/lib/icons';
+  import { BasicTable, useTable, TableAction } from '@/components/Table';
+  import { Button } from '@/components/Button';
+
+  import { useDrawer } from '@/components/Drawer';
+  import WxCardVisitDrawer from './WxCardVisitDrawer.vue';
+  import { useI18n } from 'vue-i18n';
+
+  import { columns, searchFormSchema } from './wxCardVisit.data';
+  import { getWxCardVisitList, deleteWxCardVisit } from '@/api/wechat/wxCardVisit';
+
+  export default defineComponent({
+    name: 'WxCardVisitManagement',
+    components: { BasicTable, WxCardVisitDrawer, TableAction, Button },
+    setup() {
+      const { t } = useI18n();
+      const selectedIds = ref<number[] | string[]>();
+      const showDeleteButton = ref<boolean>(false);
+
+      const [registerDrawer, { openDrawer }] = useDrawer();
+      const [registerTable, { reload }] = useTable({
+        title: t('wechat.wxCardVisit.wxCardVisitList'),
+        api: getWxCardVisitList,
+        columns,
+        formConfig: {
+          labelWidth: 120,
+          schemas: searchFormSchema,
+        },
+        useSearchForm: true,
+        showTableSetting: true,
+        bordered: true,
+        showIndexColumn: false,
+        clickToRowSelect: false,
+        actionColumn: {
+          width: 30,
+          title: t('common.action'),
+          dataIndex: 'action',
+          fixed: undefined,
+        },
+        rowKey: 'id',
+        rowSelection: {
+          type: 'checkbox',
+          columnWidth: 20,
+          onChange: (selectedRowKeys, _selectedRows) => {
+            selectedIds.value = selectedRowKeys as number[];
+            showDeleteButton.value = selectedRowKeys.length > 0;
+          },
+        },
+      });
+
+      function handleCreate() {
+        openDrawer(true, {
+          isUpdate: false,
+        });
+      }
+
+      function handleEdit(record: Recordable) {
+        openDrawer(true, {
+          record,
+          isUpdate: true,
+        });
+      }
+
+      async function handleDelete(record: Recordable) {
+        const result = await deleteWxCardVisit({ ids: [record.id] });
+        if (result.code === 0) {
+          await reload();
+        }
+      }
+
+      async function handleBatchDelete() {
+        Modal.confirm({
+          title: t('common.deleteConfirm'),
+          icon: createVNode(ExclamationCircleOutlined),
+          async onOk() {
+            const result = await deleteWxCardVisit({ ids: selectedIds.value as number[] });
+            if (result.code === 0) {
+              showDeleteButton.value = false;
+              await reload();
+            }
+          },
+          onCancel() {
+            console.log('Cancel');
+          },
+        });
+      }
+
+      async function handleSuccess() {
+        await reload();
+      }
+
+      return {
+        t,
+        registerTable,
+        registerDrawer,
+        handleCreate,
+        handleEdit,
+        handleDelete,
+        handleSuccess,
+        handleBatchDelete,
+        showDeleteButton,
+      };
+    },
+  });
+</script>

+ 72 - 0
src/views/wechat/wx_card_visit/wxCardVisit.data.ts

@@ -0,0 +1,72 @@
+import { BasicColumn, FormSchema } from '@/components/Table';
+import { useI18n } from '@/hooks/web/useI18n';
+import { formatToDateTime } from '@/utils/dateUtil';
+
+const { t } = useI18n();
+
+export const columns: BasicColumn[] = [
+  {
+    title: t('wechat.wxCardVisit.userId'),
+    dataIndex: 'userId',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardVisit.botId'),
+    dataIndex: 'botId',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardVisit.botType'),
+    dataIndex: 'botType',
+    width: 100,
+  },
+  {
+    title: t('wechat.wxCardVisit.cardInfo'),
+    dataIndex: 'cardInfo',
+    width: 100,
+  },
+  {
+    title: t('common.createTime'),
+    dataIndex: 'createdAt',
+    width: 70,
+    customRender: ({ record }) => {
+      return formatToDateTime(record.createdAt);
+    },
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    field: 'id',
+    label: 'ID',
+    component: 'Input',
+    show: false,
+  },
+  {
+    field: 'userId',
+    label: t('wechat.wxCardVisit.userId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'botId',
+    label: t('wechat.wxCardVisit.botId'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'botType',
+    label: t('wechat.wxCardVisit.botType'),
+    component: 'InputNumber',
+    required: true,
+  },
+  {
+    field: 'cardInfo',
+    label: t('wechat.wxCardVisit.cardInfo'),
+    component: 'Input',
+    required: true,
+  },
+];